2010-09-08 7 views
7

Mon application doit interroger une base de données MySQL pour de nouvelles lignes. Chaque fois que de nouvelles lignes sont ajoutées, elles doivent être récupérées. Je pensais à créer un déclencheur pour placer des références à de nouvelles lignes sur une table séparée. La table d'origine a plus de 300 000 lignes.Quel est le moyen le plus rapide d'interroger une table MySQL pour de nouvelles lignes?

L'application est construite en PHP.

Quelques bonnes réponses, je pense que la question mérite une prime.

+2

IMO, si possible, quelle que soit la couche que vous utilisez pour insérer, c'est-à-dire les services qui encapsulent les opérations CRUD, vous devez «notifier» votre application après une insertion. De cette façon, vous n'êtes pas constamment en train d'interroger. – Alex

+0

@Alex: Ce sont deux applications indépendantes différentes. La deuxième application lit uniquement à partir de la base de données. – HyderA

+1

Je dirais que le déclencheur AFTER INSERT serait sur place, implémenté au niveau MySQL, et laisserait les scripts interroger et nettoyer les nouvelles entrées dans l'autre table. De cette façon, même forcer un autre identifiant (non-auto-incrémenté) fonctionnerait toujours. – Wrikken

Répondre

7

Pour les applications externes que je trouve en utilisant une colonne TimeStamp est une méthode plus robuste qui est indépendant id automatique et d'autres questions clés primaires

Ajouter des colonnes aux tables telles que:

insertedOn TIMESTAMP DEFAULT CURRENT_TIMESTAMP 

ou pour suivre les insertions et mises à jour

updatedOn TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP 

Dans le externa l application tout ce que vous devez faire est de suivre le dernier horodatage lorsque vous avez fait un sondage. Ensuite, sélectionnez à partir de cet horodatage vers l'avant sur toutes les tables pertinentes. Dans les grandes tables, vous devrez peut-être indexer la colonne timestamp

+0

L'indexation d'un tel champ sera * toujours * bénéfique, et pas seulement dans le cas de grandes tables. +1 de toute façon. –

+0

L'indexation est généralement bénéfique. Il y a beaucoup de cas d'utilisation lorsque l'overhead de l'index n'en vaut pas la peine. – TFD

+1

Quelque chose doit être prudent avec cette solution: si l'application effectuant l'interrogation reçoit les modifications dans les lots (par exemple, SELECT * *). FROM TABLE WHERE updatedOn>: LAST_TIMESTAMP ORDER BY updateOn LIMIT 100') et il est possible que la taille du lot puisse être mise à jour en même temps (par exemple 'UPDATE TABLE SET COLUMN = 'VALEUR' O OTHER OTHER_COLUMN = 'QUELQUE CHOSE QUI CHOISIRA DES CENTAINES DE ROWS ') alors vous manquerez des rangées. – ICR

3

Vous pouvez utiliser la déclaration suivante pour savoir si un nouveau record a été inséré dans le tableau:

select max(id) from table_name 

remplaçant le nom de la clé primaire et nom de la table dans la déclaration ci-dessus. Conservez la valeur max (id) dans une variable temporaire et récupérez tous les nouveaux enregistrements entre cette dernière et la dernière valeur max (id) enregistrée. Après avoir récupéré les nouveaux enregistrements, définissez la valeur max (id) sur celle que vous avez obtenue de la requête.

+1

Pourquoi ne pas sélectionner * à partir de nom_table où id>: max –

0

En supposant que vous ayez un identifiant ou d'autres données qui grandissent toujours, vous devriez garder une trace sur votre application php du dernier identifiant récupéré.

qui fonctionnerait dans la plupart des cas. Sauf si vous êtes dans le camp en temps réel, je ne pense pas que vous auriez besoin de plus que cela.

0

Je ferais quelque chose comme ça. Bien sûr, cela suppose que l'ID est un identifiant numérique incrémentiel. Et comment vous stockez votre "emplacement actuel" dans la base de données est jusqu'à vous.

<? 
$idFile = 'lastID.dat'; 

if(is_file($idFile)){ 
    $lastSelectedId = (int)file_get_contents($idFile); 
} else { 
    $lastSelectedId = 0; 
} 

$res = mysql_query("select * from table_name where id > {$lastSelectedId}"); 

while($row = mysql_fetch_assoc($res)){ 
    // Do something with the new rows 

    if($row['id']>$lastSelectedId){ 
     $lastSelectedId = $row['id']; 
    } 
} 

file_put_contents($idFile,$lastSelectedId); 

?> 
0

Je suis d'accord avec la réponse de TFD sur le suivi d'un horodatage dans un fichier/table séparé, puis sur l'extraction de toutes les lignes plus récentes. C'est comme ça que je le fais pour une application similaire.

Votre application interrogeant une table (ou un fichier) à une seule ligne pour voir si un horodatage a été modifié à partir du stockage local ne devrait pas être très sensible aux performances. Ensuite, l'extraction de nouvelles lignes à partir de la table de lignes 300k en fonction de l'horodatage devrait à nouveau être correcte, en supposant que l'horodatage est correctement indexé. Cependant, en lisant votre question, j'étais curieux de savoir si les déclencheurs Mysql pouvaient faire des appels système, disons un script php qui soulèverait un lourd problème. Il s'avère they can en utilisant le sys_exec()User-Defined Function. Vous pouvez l'utiliser pour effectuer toutes sortes de traitements en y passant les données de ligne insérées, en ayant essentiellement une notification instantanée des insertions.

Enfin, a word of caution sur l'utilisation de déclencheurs pour appeler des applications externes.

0

Une option peut être d'utiliser une instruction INSERT INTO SELECT. En prenant des suggestions à l'aide des estampilles pour tirer les dernières lignes, vous pouvez faire quelque chose comme ...

INSERT INTO t2 (
    SELECT * 
    FROM t1 
    WHERE createdts > DATE_SUB(NOW(), INTERVAL 1 HOUR) 
); 

Cela prendriez toutes les lignes insérées dans l'heure précédente et les insérer dans le tableau 2. Vous pourriez avoir un script exécute cette requête et l'exécute toutes les heures (ou quel que soit l'intervalle dont vous avez besoin).

Ceci simplifierait considérablement votre script PHP pour tirer des lignes car vous n'auriez pas besoin de parcourir toutes les lignes. Il se débarrasse également d'avoir à suivre le dernier identifiant d'insertion.

La solution proposée par Fanis semble aussi intéressante. En tant que note, la requête de sélection dans l'insertion ci-dessus peut seulement être ajustée pour n'insérer que certains champs. Si vous avez seulement besoin de certains champs, vous devez les spécifier dans l'insert comme si ...

INSERT INTO t2 (field1, field2) (
    SELECT field1, field2 
    FROM t1 
    WHERE createdts > DATE_SUB(NOW(), INTERVAL 1 HOUR) 
); 
1

Créer un Daemon PHP pour surveiller la taille du fichier de table MySQL, si la taille change requête pour les nouveaux enregistrements, si de nouvelles les enregistrements trouvés exécutent le processus suivant.

Je pense qu'il existe un démon PEAR actif que vous pouvez facilement configurer pour surveiller la taille du fichier de table MySQL et démarrer votre script.

+1

Je ne suis pas sûr pour MySQL, mais généralement l'espace de table est alloué en morceaux, de sorte qu'une fois qu'une allocation a été faite, plusieurs lignes pourraient être ajoutées avant qu'une autre allocation ne soit nécessaire. – pascal

+0

De nombreuses tables sont dans le même fichier si vous utilisez innodb. – frodeborli

Questions connexes