【问题标题】:How can I query between two columns while still taking advantage of indexes?如何在仍然利用索引的同时在两列之间进行查询?
【发布时间】:2011-09-17 00:05:00
【问题描述】:

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

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)

【问题讨论】:

  • 您是否希望在一个查询中提交多个页面并作为结果获得一个带有与其章节配对的页码的表格?
  • 我只需要结果中的章节编号表。我不要求它们与页码配对。
  • 所以您想提交一组页码,例如 73、92、300,并希望返回 3 和 5,对吗?
  • 正确,这正是我想要的。
  • 对不起,这个让我难过。如果只有 一个 输入页面,您可以使用第二个查询,这很好,或者SELECT chapter FROM book WHERE start_page = (SELECT max(start_page) FROM book WHERE start_page &lt;= ?) AND end_page &gt;= ?。有什么方法可以修改此查询以接受多个输入?我现在根本看不到一种方法来表达输入的多个页码。有趣的问题。

标签: mysql sql indexing


【解决方案1】:

是不是就这么简单?

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

如果结束页面跟随之前的起始页面,这将起作用。

【讨论】:

    【解决方案2】:

    添加两个复合索引:

    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 将选择以列开头的索引,该列将为其扫描的剩余行数最少,然后它将索引的第二部分减少为单个所需的行(无需扫描)。

    【讨论】:

    • 我最初用我的第一个查询尝试了这个。 MySQL 并没有很好地利用这些索引,并且由于我的表的大小,我的查询平均每次几秒钟。
    • 相比之下 - 我的第二个查询在同一张表上平均为 0.0005 秒。问题当然是我一次只能查询一页。
    • 有趣。强制索引有什么影响吗?
    • 强制索引似乎没有明显的影响。
    【解决方案3】:

    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
    

    【讨论】:

    • 我用索引尝试了两个查询。第一个查询似乎平均大约 1 秒,而第二个查询平均大约 10 秒。
    猜你喜欢
    • 2014-01-14
    • 1970-01-01
    • 1970-01-01
    • 2015-02-27
    • 1970-01-01
    • 2018-03-19
    • 2011-04-18
    • 1970-01-01
    相关资源
    最近更新 更多