MySQL在大数据集上的低效查询
我们有一个类似这样的MySQL表(删除了不重要的列): 表中大约有9亿行,其中一个帐户id占这些行的65%以上。我被要求为创建的和发布的日期范围写查询,这取决于帐户id,它似乎对自动递增键有1:1的功能依赖性 典型的查询如下所示:MySQL在大数据集上的低效查询,mysql,bigdata,Mysql,Bigdata,我们有一个类似这样的MySQL表(删除了不重要的列): 表中大约有9亿行,其中一个帐户id占这些行的65%以上。我被要求为创建的和发布的日期范围写查询,这取决于帐户id,它似乎对自动递增键有1:1的功能依赖性 典型的查询如下所示: SELECT * FROM my_data WHERE account_id = 1 AND created_ts > TIMESTAMP('2012-01-01') AND created_ts <= TIMESTAMP(
SELECT *
FROM my_data
WHERE account_id = 1 AND
created_ts > TIMESTAMP('2012-01-01') AND
created_ts <= TIMESTAMP('2012-01-21')
ORDER BY created_ts DESC LIMIT 100;
问题是查询花费的时间太长,最终被终止。我已经让它运行了几次,它导致数据库主机停机,因为操作系统(Linux)的交换空间不足
我反复研究了这个问题,并试图将查询分解为不相关的子查询,强制索引,使用显式SELECT子句,并限制日期范围的窗口,但结果是一样的:性能差(太慢),主机负担太重(总是死的)
我的问题是:
感谢似乎mysql对此查询使用了错误的索引,请尝试强制执行另一个:
SELECT *
FROM my_data FORCE INDEX (`account_created_idx`)
WHERE account_id = 1 AND
created_ts > TIMESTAMP('2012-01-01') AND
created_ts <= TIMESTAMP('2012-01-21')
ORDER BY created_ts DESC LIMIT 100;
选择*
从my_数据强制索引(`account_created_idx`)
其中account_id=1和
创建时间戳(“2012-01-01”)和
创建\u ts试试MariaDB(或MySQL 5.6),因为他们的优化器可以更快地完成。
我已经用了几个月了,对于像你这样的一些查询,它比以前快了1000%
您需要索引条件下推:
不要在比较中使用函数。计算时间戳并使用计算出的值,否则您无法使用索引来比较创建的数据,而该字段将从结果集中过滤数百万行。不确定MySQL为什么使用(显然)不是最佳索引。除了强制索引外,您是否可以尝试此变体的EXPLAIN
计划:
SELECT *
FROM my_data
WHERE account_id = 1 AND
created_ts > TIMESTAMP('2012-01-01') AND
created_ts <= TIMESTAMP('2012-01-21')
ORDER BY account_id
, created_ts DESC
LIMIT 100;
选择*
从我的数据
其中account_id=1和
创建时间戳(“2012-01-01”)和
这个问题多年来一直存在。尽管如此,还是有一个很好的答案
你奋斗的关键在于你的言辞。当您执行SELECT*。。。。按X描述限制N下单
。这是因为整个结果集必须被挑选和洗牌。当您要求一个复杂表中的所有列时,这是大量的数据
对于WHERE
子句,您有一个很好的索引。如果orderby
子句中没有说DESC
,那么它对该子句也有好处
您需要的是延迟加入。首先只检索所需行的ID
SELECT auto_id
FROM my_data
WHERE account_id = 1 AND
created_ts > TIMESTAMP('2012-01-01') AND
created_ts <= TIMESTAMP('2012-01-21')
ORDER BY created_ts DESC
LIMIT 100
试试这个。这可能会为你节省很多时间
如果你先验地知道自动id和创建id都是单调递增的,那么你可以做得更好。您的子查询可以包含
ORDER BY auto_id DESC
LIMIT 100
这将减少需要进一步洗牌的数据
专业提示:避免在生产系统中选择*
;而是枚举实际需要的列。原因有很多。删除Order by子句后检查性能。MySQL 5.6不是一个稳定的版本。还没有,我知道。这只是为了增加更多的信息。我正在使用MariaDB,因为该产品正在生产阶段。非常感谢。不知道有关力索引的信息+如果可以的话。
SELECT auto_id
FROM my_data
WHERE account_id = 1 AND
created_ts > TIMESTAMP('2012-01-01') AND
created_ts <= TIMESTAMP('2012-01-21')
ORDER BY created_ts DESC
LIMIT 100
SELECT a.*
FROM my_data a
JOIN (
SELECT auto_id
FROM my_data
WHERE account_id = 1 AND
created_ts > TIMESTAMP('2012-01-01') AND
created_ts <= TIMESTAMP('2012-01-21')
ORDER BY created_ts DESC
LIMIT 100
) b ON a.auto_id = b.auto_id
ORDER BY a.created_ts DESC
ORDER BY auto_id DESC
LIMIT 100