考虑以下问题:
SELECT * FROM Transactions
WHERE day(Stamp - interval 3 hour) = 1;
Transactions 表中的标记列是TIMESTAMP,并且有一个索引。 我怎样才能更改此查询以避免全表扫描? (即,在 day()函数之外使用 Stamp )
谢谢!
答案 0 :(得分:8)
我就是这样做的:
添加一些额外的字段:YEAR,MONTH,DAY甚至HOUR,MINUTE,具体取决于您期望的流量。 然后构建一个触发器来填充额外的字段,可以提前减去3小时的间隔。 最后在额外的字段上建立一些索引。
答案 1 :(得分:1)
如果目标只是为了避免全表扫描并且您有一个PRIMARY KEY(比如名为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
)
此查询不应使用全表扫描(但是,如果表中的行数很小或者出于其他任何统计原因,优化程序可能决定使用完全扫描:))
更好的方法是使用临时表而不是子查询。
答案 2 :(得分:1)
你经常可以重写这个函数,所以你有一些看起来像WHERE Stamp=XXXX
的东西,而XXXX就是一些表达式。您可以为每个月WHERE Stamp BETWEEN timestamp('2010-01-01 00:00:00') AND timestamp ('2010-01-01 23:59:59') OR Stamp BETWEEN ...
创建一系列BETWEEN语句,但我不确定在这种情况下会使用索引。我建立了一个专栏,就像@petr建议的那样。
答案 3 :(得分:0)
在运行主查询之前单独计算所需的Stamp值,即
步骤1 - 计算所需的印记值
步骤2 - 运行查询,其中Stamp> (计算值)
由于步骤2中没有计算,您应该可以使用索引。
答案 4 :(得分:0)
如果我理解正确的话,你基本上想要返回每个月第一张邮票的所有行(减去3小时)?如果(这是一个很大的if),你有一个固定的窗口,比如说最近的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';
NB!我不确定时间戳的毫秒部分是如何工作的。您可能需要相应地填充它。
答案 5 :(得分:0)
重新处理petr的答案以避免使用IN子句,并将其用于MyISAM或InnoDB。
对于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所在的表中提取行。