是什么让这个查询如此缓慢? (MySQL 5.6.36)
What would be making this query so incredibly slow? (MySQL 5.6.36)
我有一个不断增长的数据库 table 约 800 万行 运行ning,我的应用程序定期从中获取数据。但是,查询突然开始锁定整个系统。有大量 mysqld
个进程阻塞了所有 CPU 个核心。
难道是数据库越来越大?或者下面的查询中是否有某些东西可能导致它 运行 这么长时间? UNIX_TIMESTAMP
,例如?这是慢查询日志的摘录。查询每分钟执行一次,查询时间始终在 ~7 左右。
# Query_time: 6.839524 Lock_time: 0.000170 Rows_sent: 277 Rows_examined: 7989334
FROM (
SELECT @row := @row + 1 AS `row`, `timestamp`, `price`
FROM (
SELECT @row := 0
) `derived_1`, `items`
WHERE `price` IS NOT NULL
AND `timestamp` >= UNIX_TIMESTAMP(NOW() - INTERVAL 1 DAY)
AND `currency` = 'EUR'
AND `type` = 'icon'
ORDER BY `timestamp` ASC
) `derived_2`
WHERE `row` % 8 = 0;
只是尝试一下有点困难,因为它是一个生产环境。我也无法在我的开发环境中重现该问题。
如果您需要任何其他信息,请告诉我!
提前致谢!
时间戳上的索引应该会给您带来更好的性能。特别是,因为时间戳列的值可能分布良好。货币和类型的索引可能会带来另一个性能提升。但也许您甚至没有注意到它,因为,只有几种不同的货币和数据类型(与 800 万行相比)
CREATE INDEX idx_timestamp ON items (timestamp);
是的,这需要一些时间!
UNIX_TIMESTAMP(NOW() - INTERVAL 1 DAY)
不是问题,因为它只计算了一次。
创建一个索引,以便DBMS可以快速找到记录。该索引应包含 WHERE
子句的列,从与 =
.
比较的那些列开始
CREATE idx ON items (type, currency, price, timestamp);
这甚至恰好是覆盖索引,即它包含您在查询中使用的所有列。因此 DBMS 甚至不必读取 table,因为它可以从索引本身获取所有数据。
最好的索引是:
INDEX(type, currency, -- The two columns tested via '=' (in either order)
timestamp, -- then this, for a range test
price) -- finally, the rest of the columns used
那将是一个 "covering" 索引,因此它不必在索引 BTree 和数据 BTree 之间跳动。 (其他建议的索引会因此变慢。)
希望这将使查询 运行 快于 7 秒。
运行 某些东西 "every minute" 是不安全的。如果出于某种原因,一个实例未能在一分钟内完成,会发生什么情况?可能多次调用会相互绊倒,并且可能变得越来越慢。这个可能一直堵着你体验过。
为避免这种情况,请连续 运行 工作 - 计算查询,然后睡眠,比如说 53 秒。这将(根据当前时间)非常接近每分钟一次。或者它可以暂停足够的时间以到达下一分钟(但不少于 0 秒)。
我有一个不断增长的数据库 table 约 800 万行 运行ning,我的应用程序定期从中获取数据。但是,查询突然开始锁定整个系统。有大量 mysqld
个进程阻塞了所有 CPU 个核心。
难道是数据库越来越大?或者下面的查询中是否有某些东西可能导致它 运行 这么长时间? UNIX_TIMESTAMP
,例如?这是慢查询日志的摘录。查询每分钟执行一次,查询时间始终在 ~7 左右。
# Query_time: 6.839524 Lock_time: 0.000170 Rows_sent: 277 Rows_examined: 7989334
FROM (
SELECT @row := @row + 1 AS `row`, `timestamp`, `price`
FROM (
SELECT @row := 0
) `derived_1`, `items`
WHERE `price` IS NOT NULL
AND `timestamp` >= UNIX_TIMESTAMP(NOW() - INTERVAL 1 DAY)
AND `currency` = 'EUR'
AND `type` = 'icon'
ORDER BY `timestamp` ASC
) `derived_2`
WHERE `row` % 8 = 0;
只是尝试一下有点困难,因为它是一个生产环境。我也无法在我的开发环境中重现该问题。
如果您需要任何其他信息,请告诉我!
提前致谢!
时间戳上的索引应该会给您带来更好的性能。特别是,因为时间戳列的值可能分布良好。货币和类型的索引可能会带来另一个性能提升。但也许您甚至没有注意到它,因为,只有几种不同的货币和数据类型(与 800 万行相比)
CREATE INDEX idx_timestamp ON items (timestamp);
是的,这需要一些时间!
UNIX_TIMESTAMP(NOW() - INTERVAL 1 DAY)
不是问题,因为它只计算了一次。
创建一个索引,以便DBMS可以快速找到记录。该索引应包含 WHERE
子句的列,从与 =
.
CREATE idx ON items (type, currency, price, timestamp);
这甚至恰好是覆盖索引,即它包含您在查询中使用的所有列。因此 DBMS 甚至不必读取 table,因为它可以从索引本身获取所有数据。
最好的索引是:
INDEX(type, currency, -- The two columns tested via '=' (in either order)
timestamp, -- then this, for a range test
price) -- finally, the rest of the columns used
那将是一个 "covering" 索引,因此它不必在索引 BTree 和数据 BTree 之间跳动。 (其他建议的索引会因此变慢。)
希望这将使查询 运行 快于 7 秒。
运行 某些东西 "every minute" 是不安全的。如果出于某种原因,一个实例未能在一分钟内完成,会发生什么情况?可能多次调用会相互绊倒,并且可能变得越来越慢。这个可能一直堵着你体验过。
为避免这种情况,请连续 运行 工作 - 计算查询,然后睡眠,比如说 53 秒。这将(根据当前时间)非常接近每分钟一次。或者它可以暂停足够的时间以到达下一分钟(但不少于 0 秒)。