优化SQL以获取1天数据

时间:2018-08-04 12:59:32

标签: mysql sql optimization query-optimization

我需要频繁获取最近24小时的数据,并且此查询频繁运行。 由于此操作会扫描许多行,因此经常使用它会影响数据库性能。

MySql执行策略在created_at上选择索引,并返回大约1,00,000行。然后逐行扫描这些行以过滤customer_id = 10,我的最终结果为20000行。

如何优化此查询?

explain SELECT  *
FROM    `order`
WHERE    customer_id = 10
and `created_at` >= NOW() - INTERVAL 1 DAY;

id : 1
select_type : SIMPLE
table : order
partitions : NULL
type : range
possible_keys : idx_customer_id, idx_order_created_at
key : idx_order_created_at
key_len : 5
ref : NULL
rows : 103357
filtered : 1.22
Extra : Using index condition; Using where

5 个答案:

答案 0 :(得分:1)

不是在ID和Created上创建两个单一索引,而是在(customer_id,created_at)上创建了一个综合索引。这样,索引引擎可以使用where子句的两个部分,而不仅仅是希望获得一个。向右跳到客户ID,然后直接跳到所需日期,然后给出结果。它应该非常快。

其他后续行动。 我听到了您对拥有多个索引的评论,但将其添加到主要索引中,例如

(customer_id,created_at,updated_at,completion_time)

然后,在您的查询中,总可以在where子句中为索引提供一些帮助。例如,我不知道您的具体数据。在某个给定点创建一条记录。之后,更新和完成时间将始终在此之后。从创建到完成需要多长时间(最坏的情况)... 2天,10天,90天?

where
       customerID = ?
   AND created_at >= date - 10 days
   AND updated_at >= date -1

同样,这只是一个例子,但是如果一个人有1000个订单并且周转时间相对较快,则可以跳到最近的那些,然后找到在该时间段内更新的那些。单一索引与3、4个或更多索引。

答案 1 :(得分:1)

我要做的第一个优化是对表的访问:

create index ix1 on `order` (customer_id, created_at);

然后,如果查询仍然很慢,我将尝试将您选择的列追加到索引。例如,如果要选择列order_idamountstatus

create index ix1 on `order` (customer_id, created_at, 
  order_id, amount, status);

第二种策略可能是有益的,但是您需要对其进行测试,以了解在特定情况下它可以带来哪些性能改进。

第二种策略的最大改进是,它避免回溯到表的主聚集索引(这可能是耗时的),从而仅遍历辅助索引。

答案 2 :(得分:0)

似乎您正在处理一个快速增长的表,我应该考虑将此频繁查询移至冷表或副本。

还有一点,您是否考虑过按customer_id进行分区。我不太了解查询customer_id = 10的背后的业务逻辑。如果它是多租户应用程序,请尝试分区。

答案 3 :(得分:0)

对于此查询:

SELECT o.*
FROM `order` o
WHERE o.customer_id = 10 AND
      created_at >= NOW() - INTERVAL 1 DAY;

我的第一个倾向将是(customer_id, created_at)上的综合索引-正如其他人所建议的那样。

但是,您每天似乎有很多数据和许多插入内容。这表明分区加索引。适当的分区可能位于created_at上,并且可能每天都在user_id的索引上。

典型查询将访问两个最新分区。因为您的查询集中在最近的数据上,所以这也减少了索引占用的内存,这可能是一个整体好处。

答案 4 :(得分:0)

该技术应该比所有其他答案都要好,尽管可能只是少量:

代替索引orders

PRIMARY KEY(order_id)   -- AUTO_INCREMENT
INDEX(customer_id, ...)  -- created_at, and possibly others

执行此操作以将行“聚集”在一起:

PRIMARY KEY(customer_id, order_id)
INDEX (order_id)   -- to keep AUTO_INCREMENT happy

然后,根据需要,您可以根据需要选择更多以customer_id开头的索引。是否。

另一个问题-20K行将如何处理?可以给客户带来很多,尤其是人类。如果您随后进行猛烈的修改,是否可以进行更复杂的查询,该查询执行的工作更多并且返回的行更少? 可能会更快。