【问题标题】:In SQL, what is faster: LIMIT ... OFFSET or range queries?在 SQL 中,哪个更快:LIMIT ... OFFSET 或范围查询?
【发布时间】:2021-02-15 10:51:18
【问题描述】:

给定

  • 以下架构:

    CREATE TABLE employees (
        name CHAR,
        PRIMARY KEY id INT
    );
    
  • 表格按id排序

  • 表中有 100 个从 1 到 100 的唯一 ID。


示例

| name    | id |
|---------|----|
| Lynne   | 1  |
| Johnny  | 2  |
| D'Andra | 3  |
| Kimmel  | 4  |
|        ...   |

目标

获取 10 个 id 大于或等于 3 的人。


问题

使用select name from employees order by id limit 10 offset 3select name from employees where id >= 3 and id <13 order by id 会更快吗?为什么?


到目前为止我检查过的内容

Does adding 'LIMIT 1' to MySQL queries make them faster when you know there will only be 1 result?:这表示使用限制比不使用限制要快,但它不会将其与范围查询进行比较。

Select query with offset limit is too much slow:这表示偏移量通常很慢,因为它需要遍历所有行才能到达偏移量。它没有讨论对于任何整数 x 使用 offset x 是否比 id >= x 慢?

【问题讨论】:

  • 我认为这两个 SQL 查询都应该有一个明确的 ORDER BY 子句。它不会改变任何东西,但我质疑您关于“表格按 id 排序”的断言。关系是没有定义顺序的集合。您看到的是id 作为主键的工件,MySql 已决定默认按主键顺序检索行。明天它可以做一些不同的事情。
  • 完成,谢谢@Booboo
  • 不要假设从 3 到 12 的 id 没有间隔
  • 我想你可以自己测试一下。那么你只剩下为什么的问题了?
  • @Strawberry,感谢您的评论;我一直在这里测试它:sqlfiddle.com/#!9/47da9e/3。有关如何进行更彻底测试的任何提示?在此示例中范围查询更快,但我不确定如何进行大规模测试。

标签: mysql sql performance range limit


【解决方案1】:

您的两个查询不一样。仅当您知道 id 列没有间隙并且(并且没有重复,但这对于 id 是有意义的)时,它们才是相同的。

对于小的偏移量,这样一个简单的查询应该没有区别。不过,我确实认为 MySQL 将读取 offset 查询的 all 结果,然后在达到偏移量时开始返回结果。也就是说,它实际上是计算行数,然后输出偏移后的行。

where 子句应该使 MySQL 直接转到索引中的正确记录。对于更大的结果集,这应该会更快。

【讨论】:

  • 感谢您的回答。我理解你的解释,这对我来说是有道理的,为什么 offset 现在会比 where 子句慢。我不会再接受这个答案,看看其他人是否还有什么要补充的。
  • @oamandawi 了解如何处理更大的偏移量,请参阅explainextended.com/2011/02/11/late-row-lookups-innodb
【解决方案2】:

也许这些都不是最优的。

在网页中常做的事情是“分页”,其中第一个“页面”显示“前”10 个项目,第二个页面显示接下来的 10 个项目,以此类推。

当您进入列表越来越远时,使用OFFSET 效率非常低 - 它必须小心翼翼地跨过每个“偏移”行,然后才能看到第 10 行。

如果 idAUTOINCREMENT,则无法保证 id 在一段时间内是连续的。删除、REPLACEINSERT IGNORE、集群中的复制等可能会留下空白。当然,这个数字今天很好用。但是你不应该相信明天有人“修复”了数据中的某些东西。

分页的最佳方法是“记住你离开的地方”。没有使用OFFSETid(或其他一些独特的列)只是一个占位符,不是一个数字。

更多详情:http://mysql.rjweb.org/doc.php/pagination

OP 的问题

使用 select name from employees order by id limit 10 offset 3 还是 select name from employees where id >= 3 and id

(让我修改数字以使答案更明显:)

  • limit 10 offset 300 -- 在到达所需的 10 行之前,处理必须触及 300 行;共触及 310 行。
  • where id >= 300 and id < 310 -- 假设在id 上有一个索引(可能是PRIMARY KEY),只需要触及10 行。
  • 正如我在链接中指出的那样,这避免了一个未提及的问题:如果删除了 id=305 的行怎么办?范围方法只会得到 9 行。所以...WHERE id >=300 ORDER BY id LIMIT 10 正好为您提供 10 分,并且不会被缺少的 ID 所迷惑。
  • 更好:使用LIMIT 11。这有点浪费,因为它占用了额外的一行。但它让您知道是否在页面上包含[Next] 按钮。如果您返回 11 行,则有一个“下一页”。如果

【讨论】:

  • 有道理,虽然离题有点离题。非常有用的信息,尽管如此。谢谢
  • @oamandawi - 我添加了一个很长的段落来专门解决 OP 的“问题”。我更进一步。
  • 非常感谢!我没有想到使用 where 有限制。这很聪明。我不会更改答案,因为我相信两个原始查询之间的结论仍然相同。
猜你喜欢
  • 2011-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-25
  • 1970-01-01
  • 2021-05-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多