如何在LIMIT子句中使用大偏移量加速MySQL查询?

ZA.*_*ZA. 25 mysql performance limit

在使用大偏移LIMIT的mysql 时遇到性能问题SELECT:

SELECT * FROM table LIMIT m, n;
Run Code Online (Sandbox Code Playgroud)

如果偏移m量大于1,000,000,则操作非常慢.

我必须使用limit m, n; 我不能用类似的东西id > 1,000,000 limit n.

如何优化此声明以获得更好的性能?

Pau*_*xon 13

也许您可以创建一个索引表,该表提供与目标表中的键相关的顺序键.然后,您可以将此索引表连接到目标表,并使用where子句更有效地获取所需的行.

#create table to store sequences
CREATE TABLE seq (
   seq_no int not null auto_increment,
   id int not null,
   primary key(seq_no),
   unique(id)
);

#create the sequence
TRUNCATE seq;
INSERT INTO seq (id) SELECT id FROM mytable ORDER BY id;

#now get 1000 rows from offset 1000000
SELECT mytable.* 
FROM mytable 
INNER JOIN seq USING(id)
WHERE seq.seq_no BETWEEN 1000000 AND 1000999;
Run Code Online (Sandbox Code Playgroud)

  • 此方法仅适用于不包含where条件的select语句.在我看来,这不是一个好的解决方案. (5认同)
  • 如何更新此索引表?在我的情况下,我必须按日期时间列排序并使用大偏移导致查询速度慢.如果我创建这个支持表,每次我有一个新的日期时我都需要重新插入,因为它没有按顺序排列.我已经看到了这个解决方案,但是有了临时表. (5认同)

bar*_*art 9

互联网上有一篇博客文章,说明如何最好地选择要显示的行应该尽可能紧凑,因此:只有ids; 然后生成完整的结果应该只为您选择的行获取所需的所有数据.

因此,SQL可能是这样的(未经测试,我不确定它实际上会做什么好事):

select A.* from table A 
  inner join (select id from table order by whatever limit m, n) B
  on A.id = B.id
order by A.whatever
Run Code Online (Sandbox Code Playgroud)

如果你的SQL引擎太原始而不允许这种SQL语句,或者它没有改进任何东西,而不是希望,那么将这个单个语句分解为多个语句并将id捕获到数据结构中可能是值得的.

更新:我找到了我正在谈论的博客文章:这是关于编码恐怖的杰夫阿特伍德的"所有抽象都是失败的抽象".


小智 5

如果记录很大,则缓慢可能来自加载数据.如果id列被索引,那么只选择它会快得多.然后,您可以使用IN子句为相应的id执行第二次查询(或者可以使用第一个查询中的min和max id来表示WHERE子句.)

慢:

SELECT * FROM table ORDER BY id DESC LIMIT 10 OFFSET 50000
Run Code Online (Sandbox Code Playgroud)

快速:

SELECT id FROM table ORDER BY id DESC LIMIT 10 OFFSET 50000

SELECT * FROM table WHERE id IN (1,2,3...10)
Run Code Online (Sandbox Code Playgroud)