2011-09-17 7 views
8

Immaginate Ho una tabella contiene tutti i capitoli di un libro e la pagina di inizio/fine di ogni capitolo.Come posso eseguire una query tra due colonne sfruttando ancora gli indici?

chapter | start_page  | end_page 
-------------------------------------- 
    1 |  1   | 24 
    2 |  25  | 67 
    3 |  68  | 123 
    4 |  124  | 244 
    5 |  245  | 323 

sto cercando di scoprire che cosa capitolo una pagina a caso cade su, diciamo pagina 215, per esempio.

La mia prima idea era quella di utilizzare una query come questa

SELECT `chapter` 
FROM `book` 
WHERE `start_page` <= 215 
AND `end_page` >= 215 

Purtroppo MySQL non possa trarre vantaggio degli indici nella query di sopra del quale è un grande problema a causa delle grandi dimensioni del mio tavolo.

Dopo aver fatto alcune ricerche sono arrivato fino a questa domanda che fa approfittare di indici.

SELECT `chapter` 
FROM `book` 
WHERE `start_page` <= 215 
ORDER BY `start_page` DESC  
LIMIT 1 

Il problema ora è che desidero la possibilità di eseguire query su più pagine casuali sfruttando comunque gli indici. Non sembra probabile che io possa modificare la mia ultima query poiché è così fortemente dipendente dal limitare i risultati a uno.

Qualche consiglio sarebbe molto apprezzato!

UPDATE: Grazie ad un commento da Ray Toal Ho una domanda che mi dà i risultati che ho bisogno con prestazioni sorprendenti.

SELECT chapter 
FROM book 
WHERE (start_page = (SELECT max(start_page) FROM book WHERE start_page <= 73) AND end_page >= 73) 
OR (start_page = (SELECT max(start_page) FROM book WHERE start_page <= 92) AND end_page >= 92) 
OR (start_page = (SELECT max(start_page) FROM book WHERE start_page <= 300) AND end_page >= 300) 
+0

è l'idea che si desidera, in una query, di presentare un numero di pagine e ottenere come risultato, una tabella con i numeri di pagina in coppia con il loro capitolo? –

+0

Ho solo bisogno di una tabella di numeri di capitolo nel risultato. Non ho bisogno che siano abbinati ai numeri di pagina. – Chip

+0

Quindi, in qualche modo, si desidera inviare una serie di numeri di pagina come 73, 92, un 300 e si desidera ripristinare 3 e 5, correggere? –

risposta

0

Aggiungere due indici compositi:

ALTER TABLE book 
    ADD INDEX `page_range_from_start` (start_page, end_page) 
    ADD INDEX `page_range_from_end` (end_page, start_page) 

e procedere con la query originale:

SELECT `chapter` 
FROM `book` 
WHERE 
    `start_page` <= 215 
    AND `end_page` >= 215 

MySQL sceglierà l'indice principale con la colonna che gli darà il minor numero di righe rimanenti per eseguire la scansione, e quindi avrà una seconda parte dell'indice da ridurre alla singola riga desiderata (senza una scansione).

+0

Ho provato questo con la mia prima query in origine. MySQL non sfrutta molto bene questi indici e le mie query sono in media di un paio di secondi ciascuna a causa delle dimensioni del mio tavolo. – Chip

+0

In confronto, la mia seconda query è in media di .0005 secondi sulla stessa tabella. Il problema ovviamente è il fatto che posso interrogare solo una pagina alla volta. – Chip

+0

Interessante. Costringere un indice ha qualche impatto? –

0

equivalente sintatticamente valida soluzione di Boemia INTERSECT (richiede un indice univoco di qualche tipo e di grandi dimensioni del buffer join):

SELECT 
    chapter 
FROM 
    book AS book_l 
    JOIN book AS book_r 
    USING (id) 
WHERE 
    book_l.start_page <= 215 
    AND book_r.end_page >= 215; 

O un approccio temptable (richiede un unico indice su ciascuna delle start_page e end_page):

SELECT chapter FROM (
    SELECT * FROM book WHERE start_page <= 215 
    UNION 
    SELECT * FROM book WHERE end_page >= 215 
) AS derived WHERE start_page <= 215 AND end_page >= 215 
+0

Ho provato entrambe le query con gli indici. La prima query sembra mediamente intorno al secondo mentre la seconda media in circa 10 secondi. – Chip

1

Non è così semplice come questo?

Se le pagine finali seguono pagine iniziali precedenti, funzionerà.

Problemi correlati