如何在仍然利用索引的同时在两列之间进行查询?

时间:2011-09-17 00:05:01

标签: mysql sql indexing

想象一下,我有一个表格,其中包含一本书的所有章节以及每章的开始/结束页面。

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)

3 个答案:

答案 0 :(得分:1)

这不是很简单吗?

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

如果结束页面遵循上一个开始页面,则可以使用。

答案 1 :(得分: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将选择带有列的索引,该列将为其提供最少的剩余扫描行,然后它将使索引的第二部分缩减为单个所需行(不扫描)。

答案 2 :(得分:0)

Bohemian的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和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