2011-09-17 2 views
8

Представьте, что у меня есть таблица, содержащая все главы книги и начальную/конечную страницу из каждой главы.Как я могу запросить между двумя столбцами при использовании индексов?

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

Я пытаюсь выяснить, к какой главе относится случайная страница, скажем, страница 215.

Моя первая идея состояла в том, чтобы использовать запрос, как этот

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

К сожалению, MySQL не может воспользоваться индексами в приведенном выше запросе, который является большой проблемой из-за большого размера моего стола.

После выполнения некоторых исследований я придумал этот запрос, который использует индексы.

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

Проблема теперь в том, что я хочу иметь возможность запрашивать несколько случайных страниц, все еще пользуясь индексами. Похоже, что я не могу изменить свой последний запрос, так как он настолько сильно зависит от предельных результатов.

Любой совет будет очень благодарен!

ОБНОВЛЕНИЕ: Спасибо за комментарий от Ray Toal У меня есть запрос, который дает мне результаты, которые мне нужны с потрясающей производительностью.

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

Идея, что вы хотите в одном запросе отправить несколько страниц и получить в результате таблицу со номерами страниц в паре с их главой? –

+0

Мне нужен только стол чисел глав в результате. Я не требую, чтобы они были сопряжены с номерами страниц. – Chip

+0

Итак, как-то вы хотите отправить набор номеров страниц, таких как 73, 92, 300 и хотите вернуться 3 и 5, правильно? –

ответ

0

Добавьте две составные индексы:

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

И продолжить свой первоначальный запрос:

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

MySQL будет выбрать индекс опережающих с колонкой, который даст ему наименьшее количество оставшихся строк для сканирования, а затем он будет иметь вторую часть индекса, чтобы свести к единственной требуемой строке (без сканирования).

+0

Я попробовал это с моим первым запросом изначально. MySQL не очень хорошо пользуется этими индексами, а мои запросы усредняют пару секунд каждый из-за размера моей таблицы. – Chip

+0

Для сравнения - мой второй запрос в среднем составляет .0005 секунд в одной таблице. Проблема, конечно, в том, что я могу запросить только одну страницу за раз. – Chip

+0

Интересно. Имеет ли влияние индекс? –

0

Синтаксический-действительный эквивалент INTERSECT решения богемного в (требуется уникальный индекс некоторого вида и большого присоединиться буфер):

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; 

Или в TempTable подхода (требуется один индекс по каждому из start_page и 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

Я пробовал оба запроса с индексами. Первый запрос, по-видимому, составляет около секунды, а второй - около 10 секунд. – Chip

1

Не так ли просто?

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

Если конечные страницы соответствуют предыдущим стартовым страницам, это будет работать.

Смежные вопросы