Как я могу делать запросы между двумя столбцами, все еще используя преимущества индексов? - PullRequest
8 голосов
/ 17 сентября 2011

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

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

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

Любой совет будет высоко оценен!

ОБНОВЛЕНИЕ: Благодаря комментарию Рэя Тула у меня есть запрос, который дает мне результаты, которые мне нужны, с потрясающей производительностью.

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)

Ответы [ 3 ]

1 голос
/ 17 сентября 2011

Разве это не так просто?

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

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

0 голосов
/ 17 сентября 2011

Синтаксически допустимый эквивалент решения 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;

Или подход, основанный на собеседовании (требуется один индекс для каждой из start_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 голосов
/ 17 сентября 2011

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

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 выберет индекс, начинающийся со столбца, который даст ему наименьшее количество оставшихся строк для сканирования, а затем у него будет вторая часть индекса, которая будет уменьшена до одной желаемой строки (без сканирования).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...