2010-09-08 5 views
7

La mia applicazione deve interrogare un database MySQL per nuove righe. Ogni volta che vengono aggiunte nuove righe, devono essere recuperate. Stavo pensando di creare un trigger per posizionare i riferimenti a nuove righe su una tabella separata. La tabella originale ha oltre 300.000 righe.Qual è il modo più veloce per eseguire il polling di una tabella MySQL per nuove righe?

L'applicazione è costruita in PHP.

Alcune buone risposte, penso che la domanda meriti una taglia.

+2

IMO, se possibile, qualunque strato venga utilizzato per l'inserimento, ovvero i servizi che eseguono operazioni CRUD, devono "notificare" l'applicazione dopo un inserimento. In questo modo non stai costantemente votando. – Alex

+0

@Alex: sono due diverse applicazioni indipendenti. La seconda applicazione legge solo dal database. – HyderA

+1

Direi che il trigger di AFTER INSERT dovrebbe essere azzeccato, implementare a livello MySQL e lasciare che gli script eseguano il polling e puliscano le nuove voci nell'altra tabella. In questo modo, anche forzando un altro id (non autoincrementato) funzionerebbe ancora. – Wrikken

risposta

7

Per applicazioni esterne trovo utilizzando una colonna timestamp è un metodo più robusto che è indipendente id auto e altre questioni chiave primaria

aggiungere colonne alle tabelle quali:

insertedOn TIMESTAMP DEFAULT CURRENT_TIMESTAMP 

o per rintracciare gli inserti e gli aggiornamenti

updatedOn TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP 

Nel externa L'unica cosa che devi fare è tenere traccia dell'ultimo timestamp quando hai fatto un sondaggio. Quindi selezionare da quel timestamp in avanti su tutte le tabelle pertinenti. In tabelle di grandi dimensioni potrebbe essere necessario indicizzare la colonna timestamp

+0

L'indicizzazione di tale campo * sarà * sempre utile, non solo nel caso di tabelle di grandi dimensioni. +1 comunque. –

+0

L'indicizzazione è in genere utile. Ci sono molti casi d'uso quando l'overhead dell'indice non vale la pena. Tipicamente una tabella che ha molti inserimenti e cancellazioni tra ogni selezione basata su TIMESTAMP, e la selezione basata su TIMESTAMP viene eseguita di rado – TFD

+1

Qualcosa di cui fare attenzione con questa soluzione: se l'applicazione che esegue il polling riceve le modifiche in lotti (ad es. FROM TABLE WHERE updatedOn>: LAST_TIMESTAMP ORDER BY updateOn LIMIT 100') e vi è la possibilità più che la dimensione del batch può essere aggiornata in una volta (ad esempio 'UPDATE TABLE SET COLUMN = 'VALUE' WHERE OTHER_COLUMN = 'QUALCOSA CHE SELEZIONA CENTINAIA DI ROWS'') allora ti mancheranno le file. – ICR

3

È possibile utilizzare la seguente istruzione per scoprire se un nuovo record è stato inserito nella tabella:

select max(id) from table_name 

sostituendo il nome della chiave primaria e il nome della tabella nella dichiarazione di cui sopra. Mantieni il valore massimo (id) in una variabile temporanea e recupera tutti i nuovi record tra questo e l'ultimo valore massimo (id) salvato. Dopo aver recuperato i nuovi record, imposta il valore max (id) su quello che hai ottenuto dalla query.

+1

Perché non selezionare * da nome_tabella dove id>: max –

0

supponendo che tu abbia un identificativo o altri dati che crescono sempre, dovresti tenere traccia della tua applicazione php dell'ultimo ID recuperato.

che funzionerebbe per la maggior parte degli scenari. A meno che tu non partecipi al campo in tempo reale, non penso che ti serva più di questo.

0

Farei qualcosa del genere. Ovviamente, si presume che l'ID sia un ID numerico incrementale. E come si archivia la "posizione attuale" nel database è a vostra disposizione.

<? 
$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

Concorreremo con la risposta di TFD su come tenere traccia di un timestamp in un file/tabella separato e quindi recuperare tutte le righe più nuove di quella. Ecco come lo faccio per un'applicazione simile.

L'applicazione che esegue una query su una singola riga di tabella (o file) per vedere se un timestamp è stato modificato dall'archiviazione locale non dovrebbe essere un grosso problema di prestazioni. Quindi, il recupero di nuove righe dalla tabella delle righe 300k basata sul timestamp dovrebbe essere di nuovo soddisfacente, supponendo che il timestamp sia indicizzato correttamente.

Tuttavia, leggendo la tua domanda ero curioso di sapere se i trigger di Mysql possono effettuare chiamate di sistema, ad esempio uno script php che farebbe un po 'di sollievo. Risulta they can utilizzando il sys_exec()User-Defined Function. Si può usare questo per fare tutti i tipi di elaborazione passandoci sopra i dati di riga inseriti, essenzialmente con una notifica istantanea degli inserimenti.

Infine, a word of caution sull'utilizzo di trigger per chiamare applicazioni esterne.

0

Un'opzione potrebbe essere l'utilizzo di un'istruzione INSERT INTO SELECT. Prendendo dalle suggestioni che utilizzano timestamp di tirare le ultime righe, si potrebbe fare qualcosa di simile ...

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

questo sarebbe prendere tutte le righe inserite nell'ora precedente e inserirli nella tabella 2. Si potrebbe avere uno script esegue questa query e la esegue ogni ora (o qualunque intervallo sia necessario).

Ciò semplificherebbe drasticamente lo script PHP per l'estrazione di righe poiché non è necessario eseguire iterazioni su alcuna riga. Si sbarazza anche di dover tenere traccia dell'ultimo ID di inserimento.

Anche la soluzione proposta da Fanis potrebbe sembrare interessante.

Come nota, la query di selezione nell'inserimento precedente può essere regolata per inserire solo determinati campi. Se avete solo bisogno alcuni campi, si avrebbe bisogno di specificarli nell'inserto in questo modo ...

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

Creare un PHP Daemon per monitorare la dimensione del file MySQL Table, se la dimensione cambia query per nuovi record, se il nuovo i record trovati eseguono il processo successivo.

Penso che ci sia un demone PEAR attivo che puoi facilmente configurare per monitorare la dimensione del file della tabella MySQL e dare il via allo script.

+1

Non sono sicuro per MySQL, ma di solito il tablespace è allocato in blocchi, in modo che, una volta eseguita un'allocazione, possano essere aggiunte diverse righe prima che sorga la necessità di un'altra allocazione. – pascal

+0

Molte tabelle si trovano nello stesso file se si utilizza innodb. – frodeborli