2017-09-05 41 views
2

我有MariaDB的10.1.14,很长一段时间我做没有问题下面的查询(它tooks约3秒):查询时间突然增加

SELECT 
    sum(transaction_total) as sum_total, 
    count(*) as count_all, 
    transaction_currency 
FROM 
    transactions 
WHERE 
    DATE(transactions.created_at) = DATE(CURRENT_DATE) 
    AND transaction_type = 1 
    AND transaction_status = 2 
GROUP BY 
    transaction_currency 

突然间,我不知道到底为什么这个查询需要大约13秒。
这是EXPLAIN: enter image description here

而这些都是交易表的所有索引: enter image description here

什么是突如其来的查询时间增加的原因?我该如何减少它?

+0

日期funtion在transactions.created_at是需要时间mysql不会使用索引如果列中包含函数 –

+1

我会说有些事情已经改变了。那么你改变了什么? – RiggsFolly

+0

@RiggsFolly我想到了这一点,但MAYBE唯一改变的地方是,如果AWS升级Maria次要版本,但它看起来不像它的更新。 – Michael

回答

1

+1从@JuanCarlosOropeza回答,但你可以去索引稍微进一步。

ALTER TABLE transactions ADD INDEX (
    transaction_type, 
    transaction_status, 
    created_at, 
    transaction_currency, 
    transaction_total 
); 

As @RickJames在评论中提到,列的顺序很重要。

  • 首先,列相等比较
  • 接下来,可以说被用于范围比较(这是除了任何平等)索引一个列或GROUP BY或ORDER BY。你有范围比较和GROUP BY,但你只能得到索引来帮助其中的一个。
  • 最后,查询所需的其他列,如果您认为可以获得覆盖索引。

我在我的演示文稿How to Design Indexes, Really(视频:https://www.youtube.com/watch?v=ELR7-RdU9XU)中介绍了有关索引设计的更多详细信息。

由于您有一个范围条件,并且还有一个GROUP BY引用了不同的列,所以您可能会陷入“使用临时”状态。但你至少可以通过这一招消除“使用文件排序”。

... 
GROUP BY 
    transaction_currency 
ORDER BY NULL 

假设,这不是对你很重要,其订购查询结果的行中返回

+0

非常感谢!索引实际上有帮助(不到一秒!!!),但是..这不是太具体的索引?我试图为每一列创建索引,但它给了我一点点改进,同样,为什么这个查询需要这么长时间?并感谢伟大的幻灯片和视频! – Michael

+0

这是常见的/确定只为一个查询创建索引? – Michael

+1

@Michael通常情况下,答案是肯定的,因为您希望提高响应时间,但取决于查询。请记住,创建索引占用空间并影响该表上的插入和更新。这是一种折衷。由你决定是否值得。硬盘空间非常便宜,所以不是真正的问题。 –

4

如果您要向表中添加更多数据,查询时间将会增加。

但是你可以做一些事情来提高性能。

  • 创建(transaction_type, transaction_status, created_at)
  • 从您的领域DATE()功能(或功能)的综合指数,因为不允许引擎使用索引。 CURRENT_DATE是一个常数所以无所谓,但没有必要,因为已经返回DATE
    • 如果created_at心不是日期可以使用
    • created_at >= CURRENT_DATE and created_at < CURRENT_DATE + 1
    • 或创建一个不同的领域仅保存日期部分。
+0

你的答案在DATE()比我的问题更明确。很好解释。 –

+0

但指数倒退。 “范围”部分('created_at')需要是最后一个。 –

+0

@RickJames你确定吗?看起来没问题。你会建议什么? –

0

我不知道是什么使您的查询慢。更多数据?不成?新的数据库版本?

但是,我很惊讶地发现没有真正支持查询的索引。您应该有一个以最高基数的列开始的复合索引(日期?那么您可以尝试不同的列顺序并查看DBMS为查询选择哪个索引)。

create index idx1 on transactions(created_at, transaction_type, transaction_status); 

如果created_at包含日期的一部分,那么你可能要创建一个计算列created_on只包含日期和索引来代替。

您可以将这个指标甚至扩展到覆盖索引(其中后面组子句领域by子句场其后SELECT子句字段):

create index idx2 on transactions(created_at, transaction_type, transaction_status, 
            transaction_currency, transaction_total);