考虑下面的查询:优化SQL查询,以避免全表扫描
SELECT * FROM Transactions
WHERE day(Stamp - interval 3 hour) = 1;
在交易表中的邮票列是TIMESTAMP和有它的索引。 如何更改此查询以避免全表扫描? (即使用邮票以外的天()函数)
谢谢!
考虑下面的查询:优化SQL查询,以避免全表扫描
SELECT * FROM Transactions
WHERE day(Stamp - interval 3 hour) = 1;
在交易表中的邮票列是TIMESTAMP和有它的索引。 如何更改此查询以避免全表扫描? (即使用邮票以外的天()函数)
谢谢!
如果目标仅仅是避免全表扫描,你必须为交易主键(说叫PK),考虑增加覆盖指数
ALTER TABLE Transactions ADD INDEX cover_1 (PK, Stamp)
然后
SELECT * FROM Transactions WHERE PK IN (SELECT PK FROM Transactions
WHERE day(Stamp - interval 3 hour) = 1
)
该查询应不使用全表扫描(但是优化器可以决定使用全扫描,如果表格中的行数很少或者出于任何其他统计原因:))
更好的方式ma y是使用临时表而不是子查询。
分别计算你所需的邮票值运行您主查询之前,即
步骤1 - 计算期望印记值
第2步 - 运行查询,其中邮票>(计算值)
因为在步骤2中没有计算,您应该可以使用您的索引。
你可以经常重写函数,所以你看起来像WHERE Stamp=XXXX
,而XXXX是一些表达式。您可以为每个月创建一系列BETWEEN语句,WHERE Stamp BETWEEN timestamp('2010-01-01 00:00:00') AND timestamp ('2010-01-01 23:59:59') OR Stamp BETWEEN ...
,但我不确定在这种情况下会使用索引。我会按照@petr的建议创建一个月份的那一天。
如果我理解正确,你基本上想要返回邮票落在每个月的第一个(减去3小时)的所有行?如果(这是一个很大的话),你有一个固定的窗口,比如最近6个月,你可以列举6个范围测试。但是,我仍然不确定索引访问会更快。
select *
from transactions
where stamp between timestamp '2010-06-01 03:00:00' and timestamp '2010-06-02 02:59:59'
or stamp between timestamp '2010-07-01 03:00:00' and timestamp '2010-07-02 02:59:59'
or stamp between timestamp '2010-08-01 03:00:00' and timestamp '2010-08-02 02:59:59'
or stamp between timestamp '2010-09-01 03:00:00' and timestamp '2010-09-02 02:59:59'
or stamp between timestamp '2010-10-01 03:00:00' and timestamp '2010-10-02 02:59:59'
or stamp between timestamp '2010-11-01 03:00:00' and timestamp '2010-11-02 02:59:59'
or stamp between timestamp '2010-12-01 03:00:00' and timestamp '2010-12-02 02:59:59';
注意!我不确定时间戳的毫秒部分是如何工作的。您可能需要相应地填充它。
为了避免IN子句以及为MyISAM或InnoDB创建它,稍加修改petr的回答。
对于MyISAM
ALTER TABLE Transactions ADD INDEX cover_1 (PK, Stamp)
或者,InnoDB的,其中PK是隐含在每一个指标,
ALTER TABLE Transactions ADD INDEX Stamp (Stamp)
然后
SELECT *
FROM Transactions LEFT JOIN
(
SELECT PK
FROM Transactions
WHERE DAYOFMONTH(Stamp - interval 3 hour) = 1
) a ON Transactions.PK=a.PK
子查询将有一个索引只执行,并且外部查询将只从a.PK通过的表中提取行。
我不是要求“功能索引” - 它们不存在。 相反,我想转换这个查询以相同的方式,你可以将“SELECT * FROM table WHERE sqrt(column)= 2”转换为“SELECT * FROM table WHERE column = 4” – emx 2010-12-02 13:15:34