2016-03-24 10 views
11

Ho tabella in MySQL con 10 milioni di righe con 2 GB di dati Selezione nei dati formato LIFO è lento motore2GB con 10 milioni di righe, ritardo impaginazione selezionare è lento

Tabella è = InnoDB

tavolo ha una primaria chiave e uno unica chiave

SELECT * FROM link LIMIT 999999 , 50; 

come migliorare le prestazioni della tabella. ?

struttura della tabella

id int(11) NO PRI NULL auto_increment 
url varchar(255) NO UNI NULL  
website varchar(100) NO  NULL  
state varchar(10) NO  NULL  
type varchar(100) NO  NULL  
prio varchar(100) YES  NULL  
change varchar(100) YES  NULL  
last varchar(100) YES  NULL 

NOTA: SELECT * FROM link LIMIT 1 , 50; sta prendendo .9ms ma SQL corrente sta prendendo 1000ms suo 100 tempo di prendere più

+0

Avete bisogno di tutte le colonne della tabella Puoi approfondire slowness- Quanto tempo sta prendendo? Inoltre, qual è il tipo di dati delle colonne? – Sanj

+0

si può eseguire sotto query e incollare il risultato 'SPIEGARE SELECT * FROM collegamento LIMIT 999999, 50;' –

+0

suoi quasi prendere 1 secondo, ma quando nessuno di fila sarà più grande allora il tempo andare a prendere il tempo sarà più SELECT * DA link LIMIT 1, 50; sta prendendo .9ms ma lo sql corrente sta prendendo 1000ms la sua 100 volta che prende più. –

risposta

4

Questo molto probabilmente è dovuto alla "ricerca di fila presto"

MySQL può essere forzato a eseguire "late row lookup". Prova sotto interrogazione

SELECT l.* 
FROM (
     SELECT id 
     FROM link 
     ORDER BY 
       id 
     LIMIT 999999 , 50 
     ) q 
JOIN link l 
ON  l.id = q.id 

controllare questo articolo

MySQL limit clause and rate low lookups

+2

Non ci credevo, fino a testarlo da solo. Nel mio test è stata la vittoria del 50% delle prestazioni. Perché MySQL non è ancora in grado di ottimizzare tali query senza aiuto? –

+0

@PaulSpiegel: È stata una sorpresa anche per me quando l'ho incontrata per la prima volta. – Sanj

0

Ho aggiornato il mio query SQL per questo e questo sta prendendo meno quantità di tempo.

SELECT * FROM link ORDER BY id LIMIT 999999 , 50 ; 
5

Per la Successiva e Prec pulsanti è possibile utilizzare una clausola WHERE invece di OFFSET.

Esempio (usando LIMIT 10 - i dati del campione ha spiegato di seguito): Siete sulla qualche pagina che mostra 10 file con gli ID [2522,2520,2514,2513,2509,2508,2506,2504,2497,2496]. Questo nel mio caso viene creato con

select * 
from link l 
order by l.id desc 
limit 10 
offset 999000 

Per la pagina successiva si usa

limit 10 
offset 999010 

ottenere file con ID [2495,2494,2493,2492,2491,2487,2483,2481,2479,2475].

Per la pagina precedente usereste

limit 10 
offset 998990 

ottenere righe con ids [2542,2541,2540,2538,2535,2533,2530,2527,2525,2524].

Tutte le query precedenti vengono eseguite in 500 msec. Usando il "trucco" suggerito da Sanj ci vuole ancora 250 msec.

Ora, con l'determinata pagina con minId=2496 e maxId=2522 possiamo creare le query per le Successiva e Ultimi pulsanti utilizzando la clausola WHERE.

pulsante Avanti:

select * 
from link l 
where l.id < :minId -- =2496 
order by l.id desc 
limit 10 

ids risultante: [2495,2494,2493,2492,2491,2487,2483,2481,2479,2475].

pulsante Indietro:

select * 
from link l 
where l.id > :maxId -- =2522 
order by l.id asc 
limit 10 

ids risultante: [2524,2525,2527,2530,2533,2535,2538,2540,2541,2542].

per invertire l'ordine è possibile utilizzare la query in un sub-SELECT:

select * 
from (
    select * 
    from link l 
    where l.id > 2522 
    order by l.id asc 
    limit 10 
) sub 
order by id desc 

risultanti ids: [2542,2541,2540,2538,2535,2533,2530,2527,2525,2524].

Queste query vengono eseguite in "nessun tempo" (meno di 1 msec) e forniscono lo stesso risultato.

Non è possibile utilizzare questa soluzione per creare numeri di pagina. Ma non penso che produrrai numeri di pagina di 200K.

dati di test:

dati utilizzati per l'esempio e parametri di riferimento è stato realizzato con

CREATE TABLE `link` (
    `id` INT(11) NOT NULL AUTO_INCREMENT, 
    `url` VARCHAR(255) NOT NULL, 
    `website` VARCHAR(100) NULL DEFAULT NULL, 
    `state` VARCHAR(10) NULL DEFAULT NULL, 
    `type` VARCHAR(100) NULL DEFAULT NULL, 
    `prio` VARCHAR(100) NULL DEFAULT NULL, 
    `change` VARCHAR(100) NULL DEFAULT NULL, 
    `last` VARCHAR(100) NULL DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE INDEX `url` (`url`) 
) COLLATE='utf8_general_ci' ENGINE=InnoDB; 

insert into link 
    select i.id 
     , concat(id, '-', rand()) url 
     , rand() website 
     , rand() state 
     , rand() `type` 
     , rand() prio 
     , rand() `change` 
     , rand() `last` 
    from test._dummy_indexes_2p23 i 
    where i.id <= 2000000 
     and rand() < 0.5 

dove test._dummy_indexes_2p23 è una tabella contenente 2^23 ids (circa 8M). Quindi i dati contengono circa 1 milione di righe che a caso mancano ogni secondo id. Dimensioni della tavola: 228 MB

0

Prima di tutto in esecuzione sul vostro tavolo senza alcun ordine non garanzia la query restituirà gli stessi dati, se eseguito due volte. È meglio aggiungere una clausola ORDER BY. Prendendo il id come un buon candidato, dato che è la tua chiave primaria e sembra univoco (dato che è un valore auto_increment).

È possibile utilizzare questo come base:

SELECT * FROM link ORDER BY id LIMIT 50; 

questo vi darà le prime 50 righe della tabella.

Ora per le successive 50 righe, invece di utilizzare OFFSET, potremmo salvare la nostra ultima posizione nella query.

Si potrebbe salvare l'ID dall'ultima fila ultima id dalla query precedente e utilizzarlo nella prossima query:

SELECT * FROM link WHERE id > last_id ORDER BY id LIMIT 50; 

questo vi darà i prossimi 50 righe dopo l'ultimo id.

La ragione per la query gira lentamente su valori elevati di OFFSET è perché mysql deve essere eseguito su tutte le righe della data OFFSET e restituire l'ultimo LIMIT numero di righe. Ciò significa che il più grande OFFSET è il più lento che verrà eseguita la query.

La soluzione che ho mostrato sopra, non dipende da OFFSET, quindi la query verrà eseguita alla stessa velocità indipendentemente dalla pagina corrente.

Vedi anche questo articolo utile che spiega alcune altre opzioni è possibile scegliere tra: http://www.iheavy.com/2013/06/19/3-ways-to-optimize-for-paging-in-mysql/