2009-06-24 8 views
1

je mettre en place un cache de mémoire pour une table qui ressemble à ceci (simplifié):requête MySQL le plus efficace pour mettre à jour une table de la table de mémoire identique

Item1 (entier), Item2 (entier), cnt (Entier

La table d'origine comprend des millions de paires comme ceci. et il met à jour rapidement.

Pour rendre tout cela plus efficace, je veux écrire de nouvelles paires dans une table de mémoire identique et mettre à jour périodiquement la vraie table sur disque par cron.

Le cron devrait faire ce qui suit: pour chaque paire s'il y a une paire similaire dans la table non-mémoire, augmenter le compte par le compte de la table de la mémoire. Si aucune paire n'existe, créez-la avec count à partir de la table de mémoire.

Comment puis-je rendre le vidage (de la table de mémoire à la table réelle) le plus efficace?

Remarques: L'environnement est Mysql 5.0.45 PHP 5.2.6 CentOS

Répondre

3

Vous pouvez utiliser une requête INSERT ... ON DUPLICATE KEY UPDATE - mais cela dépend des clés primaires ou UNIQUE index sur votre table principale.

INSERT 
    INTO <<master_table>> (Item1, Item2, cnt) 
    SELECT Item1, Item2, cnt FROM <<memory_table>> 
    ON DUPLICATE KEY UPDATE cnt = cnt + VALUES(cnt); 
+0

Essayer d'éditer ma réponse mais il semble que parce que j'ai supprimé l'anwser et l'a supprimé par la suite, SO empêche toute autre édition (erreur "non trouvé"; peut-être un problème de mise en cache). La commande ON DUPLICATE KEY UPDATE doit indiquer "ON DUPLICATE KEY UPDATE" cnt = cnt + VALUES (cnt) si cnt n'est pas toujours 1 dans la table de la mémoire. –

+0

Merci! Ça marche. Cependant quelque chose me semble étrange. La solution qui a fonctionné pour moi est "INSERT INTO linked_items SELECT * FROM linked_items_mem comme li_mem SUR DUPLICATE KEY UPDATE linked_items.cnt = linked_items.cnt + li_mem.cnt;" Cependant dans mes tests la table de mémoire a 26 rangées mais mysql indique que 48 rangées ont été affectées. Comment venir? – Nir

+1

@Nir: Chaque opération INSERT et UPDATE compte séparément. Dans votre cas, il y avait 26 INSERT, dont 22 ont échoué et ont conduit à 22 UPDATE, faisant ainsi 26 + 22 = 48 opérations. – Quassnoi

2

Créer une PRIMARY KEY sur la table de disque:

ALTER TABLE maintable ADD CONSTRAINT pk_maintable_item1_item2 (item1, item2) 

et exécutez la requête suivante:

INSERT 
INTO maintable 
SELECT item1, item2, COUNT(*) AS cnt 
FROM memtable mem 
GROUP BY 
     item1, item2 
ON DUPLICATE KEY 
UPDATE cnt = maintable.cnt + mem.cnt 

Notez toutefois que si vous avez beaucoup de DISTINCT item1, item2 paires, puis les solution proposé par @S. Gehrig fonctionnera probablement mieux (en raison de frais généraux sur GROUP BY)

+0

J'aime cette idée de regrouper les lignes avant l'insertion. +1 –

+0

@S. Gehrig: Ça ne marchera pas sans ça. MySQL peut mettre à jour chaque ligne dans une table au plus une fois dans une seule requête de mise à jour, voir ceci: bugs.mysql.com/bug.php?id=44494 – Quassnoi

+0

@Quassnoi: Merci pour cette info. J'ai supprimé ma réponse car elle ne fonctionnerait pas en fonction du rapport de bug ci-dessus. –

Questions connexes