2011-12-11 69 views
3

我有一张int字段的表,我们称之为createTime。该表由几百万条记录组成。现在我想运行查询:偏差限制(“LIMIT 500000,10”)即使在索引后也很慢?

select * from `table` order by `createTime` desc limit 500000, 10 

我创建了一个指数为createTime,但在查询运行慢得令人难以置信。什么原因?我该如何改进它?

这里是EXPLAIN说:

id 1 
select_type simple 
table table 
type index 
possible_keys null 
key createTime 
key_len 4 
ref null 
rows 500010 
extra 

至于补偿,它的工作速度更快时,它的小。

+0

您是否尝试过使用EXPLAIN关键字查看MySql正在做什么?实际上,EXPLAIN从'table'命令中选择* by createTime' desc limit 500000,10.出于兴趣,什么数据类型是createTime? – dash

+0

我在问题中解释过这是一个int。 EXPLAIN表示没有什么有趣的地方,它使用创建的索引,它估计的行数为500010. –

+0

(索引创建之前*的性能是怎样的?什么是没有偏移的限制?偏移量更小的限制?) – 2011-12-11 20:42:29

回答

8

一般规则:avoid OFFSET for large tables

[A] S上的偏移量增加时,所采取的查询执行 逐渐增加,这可能意味着处理非常大的表 将需要极长的时间。原因是因为抵消工作 对表未被索引的表中的行的物理位置。因此 要在偏移量x处查找一行,数据库引擎必须遍历从0到x遍历 的所有行。

一般的经验法则是“从来没有在限制子句中使用补偿”。对于 小型表格,您可能不会注意到任何区别,但对于具有超过一百万行的表格 ,您将看到性能提高 。

+2

我宁愿*“避免大OFFSET”* –

+0

@ypercube:但大'OFFSET'为小桌子很好。 –

+0

你的意思是当OFFSET大于表格大小?我猜就是这样。毫无意义但很好。 –

0

我认为索引不会改变任何东西。使用offset, limit表示“读取偏移量+限制数据集并丢弃它们的偏移量”。如果你真的想为这样一个大表分页或类似的东西,你应该使用一种方法,你可以将结果限制在查询的WHERE部分。这些类型的查询将受益于正确的索引。

使用日期时间,解决方案可能是使用时间段来显示数据。例如。你可以显示每周的每一天的链接,并建立你的查询,如“WHERE createDate>'2011-12-11'和crateDate <'2011-12-12'。

2

如果你有一个。唯一的列在理想情况下将它createTime本身:

SELECT "table".* 
    FROM "table" 
    INNER JOIN (
    SELECT "createTime" 
     FROM "table" 
     ORDER BY "createTime" DESC 
     LIMIT 500000, 10 
) AS "limit" ON "table"."createTime" = "limit"."createTime" 

如果createTime不是唯一的,但你有另一列,它是独一无二的,那么你会发现你需要创建在createTime一个综合指数和您的另一列命令此查询有效运行:

SELECT "table".* 
    FROM "table" 
    INNER JOIN (
    SELECT "createTime", "unique" 
     FROM "table" 
     ORDER BY "createTime" DESC 
     LIMIT 500000, 10 
) AS "limit" ON "table"."unique" = "limit"."unique" 
+1

谢谢,但这个查询仍然需要几秒钟才能运行。对于一个网站来说这是不可接受的。没有更快的方法来实现基于createTime列的分页吗? –

相关问题