2011-09-17 10 views
8

Wyobraź sobie, że mam tabelę zawierającą wszystkie rozdziały książki i stronę początkową/końcową z każdego rozdziału.Jak mogę wykonać zapytanie między dwiema kolumnami, jednocześnie korzystając z indeksów?

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

Próbuję dowiedzieć się, na jaki rozdział przypada przypadkowa strona, na przykład strona 215.

Moim pierwszym pomysłem było użyć kwerendy jak ten

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

Niestety MySQL nie mogą skorzystać z indeksami w powyższej kwerendy, która jest dużym problemem ze względu na duże rozmiary moim stole.

Po przeprowadzeniu badań wpadłem na to zapytanie, które wykorzystuje indeksy.

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

Problem polega na tym, że chcę mieć możliwość wysyłania zapytań na wiele losowych stron przy jednoczesnym korzystaniu z indeksów. Nie wydaje mi się prawdopodobne, że mogę zmodyfikować moje ostatnie zapytanie, ponieważ jest tak mocno uzależnione od ograniczania wyników do jednego.

Każda rada byłaby mile widziana!

UPDATE: Dzięki komentarzem Ray Toal Mam kwerendy, która daje mi wyniki muszę z niezwykłą wydajność.

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

Czy w jednym zapytaniu chciałbyś przesłać kilka stron i uzyskać w rezultacie tabelę z numerami stron sparowanymi z ich rozdziałem? –

+0

Potrzebuję tylko tabeli numerów rozdziałów w wyniku. Nie wymagam ich sparowania z numerami stron. – Chip

+0

Więc jakoś chcesz przesłać zestaw numerów stron jak 73, 92, 300 i chcesz odzyskać 3 i 5, prawda? –

Odpowiedz

0

Dodaj dwóch syntetycznych wskaźników:

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

i postępować z oryginalnego zapytania:

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

MySQL wybrać indeks prowadzącą z kolumny, które dadzą mu najmniejszą liczbę pozostałych wierszy do skanowania, a następnie będzie mieć drugą część indeksu, aby zmniejszyć do jednego pożądanego wiersza (bez skanowania).

+0

Próbowałem tego z pierwszym zapytaniem pierwotnie. MySQL nie wykorzystuje bardzo dobrych zalet tych indeksów, a moje zapytania średnio wynoszą po kilka sekund ze względu na rozmiar mojego stołu. – Chip

+0

Dla porównania - moje drugie zapytanie wynosi 0,0005 sekundy na tej samej tabeli. Kwestią oczywiście jest to, że mogę zapytać tylko o jedną stronę na raz. – Chip

+0

Interesujące. Czy wymuszenie indeksu ma jakikolwiek wpływ? –

0

składniowo, ważne równoważnik INTERSECT roztworu bohemską w (warunek wyjątkowy współczynnik pewnego rodzaju i dużej buforze przyłączenia):

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; 

lub A Temptable podejścia (wymaga jednego indeksu każdej start_page i 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

Próbowałem obu zapytań z indeksami. Pierwsze zapytanie wydaje się średnio około sekundy, podczas gdy drugie średnio około 10 sekund. – Chip

1

Czy to nie jest takie proste?

select max(chapter) 
from book 
where start_page <= 215; 

Jeśli strony końcowe śledzą poprzednie strony początkowe, to zadziała.

Powiązane problemy