Tom, thank you so much for the extensive advice. Ian
On 04/06/2011 15:27, BareFeetWare wrote: > On 03/06/2011, at 11:40 PM, Ian Hardingham wrote: > >> Hey guys, thank you very much for the help so far. >> >> The list of calls which I make during the "end match section", which can >> take 2 seconds, is: >> >> SELECT * FROM multiturnTable WHERE id=? LIMIT 1 >> >> UPDATE multiturnTable SET p1SubmitScore=1 WHERE id=? >> >> UPDATE multiturnTable SET complete=1, score=? WHERE id=? >> >> SELECT * FROM userTable WHERE name='?' twice >> >> UPDATE userTable SET totalScore=?, totalRecord='?', dailyScore=?, >> dailyRecord='?', dailyGameRecord='?', dailyGamesPlayed='?', >> scoreStreak='?', scoreStreakNumber=? WHERE name='?'; twice > If properly constructed, I would expect this to be almost instant. > > I suggest: > > 1. Use integer columns instead of text for id primary key > 2. Use foreign keys (ie "references") > 3. Atomize your columns, ie only one piece of data per column (eg don't store > record as number tab number in one column). > 4. For any column that is multiple choice (eg status), don't store as text, > store as an integer that references another table. > 5. In general, properly normalise your tables, which includes the above. It's > hard to be more precise without knowing your data better. > 5. Use triggers to update the related user table when a match changes (eg > ends). > 6. Do all of an event in one transaction. > 7. Do it all (or as much as possible) of an event in SQL, rather than passing > values back from SQL into application then back to SQL. > > At the basic level, do the foloowing: > > Change multiturnTable to this (I've only really changed the first three > columns): > > create table multiturnTable > ( id integer primary key not null > , player1 integer not null references userTable(id) > , player2 integer not null references userTable(id) > , date text > , rating real > , info text > , complete integer > , currentTurn integer > , p1Submitted integer > , p2Submitted integer > , score real > , gamemode text > , turnLimit integer > , turnTimeLimit integer > , p1SubmitScore integer > , p2SubmitScore integer > , quickMatchId integer > , nComments integer default 0 > , p1TurnSubTime real > , p2TurnSubTime float > , nRatings integer > , p1GivenUp integer > , p2GivenUp integer > , dupId integer default -1 > , p1Declined integer default 0 > , p2Declined integer default 0 > , lastP1CommitTime text default '-1' > , lastP2CommitTime text default '-1' > ) > ; > > Change userTable to this: > > create table userTable > ( id integer primary key not null > , name text not null unique collate nocase > , email text collate nocase > , key text > , status text > , date text > , playedFor integer > , totalScore real default 0 > , totalRecordHigh integer default 0 > , totalRecordLow integer default 0 > , dailyScore real default 0 > , dailyRecordHigh integer default 0 > , dailyRecordLow integer default 0 > , dailyGameRecordHigh integer default 0 > , dailyGameRecordLow integer default 0 > , dailyGamesPlayed integer default 0 > , scoreStreak text default '' > , scoreStreakNumber integer default 0 > , noEmail integer default 0 > , playedInfIds text default '' > ) > ; > > -- These calculations are guesses. You will need to correct them: > > create trigger multiturnEndMatch > after update of complete > on multiturnTable > when new.complete = 1 and old.complete != 1 > begin > update userTable > set totalScore = totalScore + new.p1SubmitScore > , dailyScore = dailyScore + new.p1SubmitScore > , dailyGamesPlayed = dailyGamesPlayed + 1 > , scoreStreak = scoreStreak + new.p1SubmitScore > , scoreStreakNumber = scoreStreakNumber + 1 > where id = old.player1 > ; > update userTable > set totalScore = totalScore + new.p2SubmitScore > , dailyScore = dailyScore + new.p2SubmitScore > , dailyGamesPlayed = dailyGamesPlayed + 1 > , scoreStreak = scoreStreak + new.p2SubmitScore > , scoreStreakNumber = scoreStreakNumber + 1 > where id = old.player2 > ; > -- if player1 won: > update userTable > set totalRecordHigh = new.p1SubmitScore > , totalRecordLow = totalRecordLow + new.p2SubmitScore > where new.p1SubmitScore> new.p2SubmitScore and totalRecordHigh< > new.p1SubmitScore > ; > update userTable > set dailyRecordHigh = new.p1SubmitScore > , dailyRecordLow = new.p2SubmitScore > where new.p1SubmitScore> new.p2SubmitScore and dailyRecordHigh< > new.p1SubmitScore > ; > update userTable > dailyGameRecordHigh = new.p1SubmitScore > , dailyGameRecordLow = new.p2SubmitScore > where new.p1SubmitScore> new.p2SubmitScore and dailyGameRecordHigh< > new.p1SubmitScore > ; > -- if player2 won: > update userTable > set totalRecordHigh = new.p2SubmitScore > , totalRecordLow = totalRecordLow + new.p1SubmitScore > where new.p2SubmitScore> new.p1SubmitScore and totalRecordHigh< > new.p2SubmitScore > ; > update userTable > set dailyRecordHigh = new.p2SubmitScore > , dailyRecordLow = new.p1SubmitScore > where new.p2SubmitScore> new.p1SubmitScore and dailyRecordHigh< > new.p2SubmitScore > ; > update userTable > dailyGameRecordHigh = new.p2SubmitScore > , dailyGameRecordLow = new.p1SubmitScore > where new.p2SubmitScore> new.p1SubmitScore and dailyGameRecordHigh< > new.p2SubmitScore > ; > end > ; > > > Then your end match SQL becomes simply one SQL statement: > > update multiturnTable set complete = 1 where id = ? > > That will fire the trigger to update the user data, which all occurs in one > transaction. > > Another option worth considering is to not store and update the individual > user game history data in the userTable at all. You could simply cross > reference and perform calculations on the multiturn table when needed. This > saves you from having to keep tables in sync and updated, and eliminates > redundant data. The speed is potentially slower, but you probably won't > notice with indexes on player1 and player2. > > So, for instance, when wanting the stats for a particular user, you could do > this: > > select > userTable.id > , userTable.name > , sum(player1.p1SubmitScore) + sum(player2.p2SubmitScore) as totalScore > , max(max(player1.p1SubmitScore), max(player2.p2SubmitScore)) as > totalRecordHigh > from userTable > left join multiturnTable as player1 on userTable.id = > multiturnTable.player1 > left join multiturnTable as player2 on userTable.id = > multiturnTable.player2 > where userTable.id = ? and multiturnTable.complete = 1 > ; > > I hope this helps. > > Tom > BareFeetWare > > -- > Comparison of SQLite GUI tools: > http://www.barefeetware.com/sqlite/compare/?ml > -- > iPhone/iPad/iPod and Mac software development, specialising in databases > develo...@barefeetware.com > _______________________________________________ sqlite-users mailing list sqlite-users@sqlite.org http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users