【问题标题】:what index(es) needs to be added for this query to work properly?需要添加哪些索引才能使此查询正常工作?
【发布时间】:2011-04-18 04:10:24
【问题描述】:

这个查询在我的慢查询日志中弹出:

SELECT
  COUNT(*)                 AS ordersCount,
  SUM(ItemsPrice + COALESCE(extrasPrice, 0.0)) AS totalValue,
  SUM(ItemsPrice)          AS totalValue,
  SUM(std_delivery_charge) AS totalStdDeliveryCharge,
  SUM(extra_delivery_charge) AS totalExtraDeliveryCharge,
  this_.type               AS y5_,
  this_.transmissionMethod AS y6_,
  this_.extra_delivery     AS y7_
FROM orders this_
WHERE this_.deliveryDate BETWEEN '2010-01-01 00:00:00' AND '2010-09-01 00:00:00'
    AND this_.status IN(1, 3, 2, 10, 4, 5, 11)
    AND this_.senderShop_id = 10017
GROUP BY this_.type, this_.transmissionMethod, this_.extra_delivery
ORDER BY this_.deliveryDate DESC;

该表是 InnoDB,大约有 880k 行,执行时间在 9-12 秒之间。我尝试添加以下索引ALTER TABLE orders ADD INDEX _deliverydate_senderShopId_status ( deliveryDate , senderShop_id , status, type, transmissionMethod, extra_delivery);,但没有任何实际收获。欢迎任何帮助和/或建议

这是现在的查询执行计划:

id select_type 表类型 possible_keys key key_len ref rows 已过滤 Extra 1 SIMPLE this_ref FKC3DF62E57562BA6F 8 const 139894 100.00 使用where;使用临时的;使用文件排序

我从文本中取出了 possible_keys 值,因为我认为它列出了表中的所有索引。使用的密钥(FKC3DF62E57562BA6F)看起来像

键名类型唯一压缩字段基数排序空注释 FKC3DF62E57562BA6F BTREE 否 否 senderShop_id 4671 A

【问题讨论】:

  • deliveryDate的列类型是什么?
  • 索引应该与查询计划的分析一起完成,以查看它们是如何被真正使用的。基于数据库完成的优化,数据库将如何使用索引并不总是很明显。使用此索引发布您的查询计划,然后我们将能够更好地提供帮助
  • @Thilo - deliveryDate 是日期时间
  • 是否正在使用索引?应该是,但是您可以在 where 子句中尝试明确的 to_date 吗?另外,所有列都不是 NULL 吗?
  • @In Sane - 我编辑了问题并添加了查询执行计划

标签: mysql indexing performance


【解决方案1】:

我会告诉你一件可以提高速度的事情。

对于未知或不适用的行,数据中通常只有 NULL 值。在我看来,既然您将NULL 视为0 无论如何,您应该考虑摆脱它们并确保所有extrasPrice 值都是0,它们以前是NULL,这样你可以摆脱coalesce的时间惩罚。

事实上,您可以更进一步,引入名为totalPrice另一个 列,您可以使用插入/更新触发器将其设置为实际值ItemsPrice + extrasPrice 或(ItemsPrice + COALESCE(extrasPrice,0.0),如果您仍然需要extrasPrice 的可空性)。

然后,您可以简单地使用:

SELECT
    COUNT(*)          AS ordersCount,
    SUM(totalPrice)   AS totalValue,
    SUM(ItemsPrice)   AS totalValue2,
    :

(我不确定您是否应该有两个具有相同名称的输出列,或者这是否是拼写错误,在最坏的情况下,这将是一个错误,至多是令人困惑的)。

这将计算成本转移到插入/更新时间而不是选择时间,并摊销所有选择的成本 - 大多数数据库表的读取频率远高于写入频率。由于触发器,数据的一致性得以保持,性能应该更好,但代价是一些存储需求。

但是,由于绝大多数数据库问题是“我怎样才能获得更快的速度?”而不是“我怎样才能使用更少的磁盘?”,这通常是个好主意。

另一个建议是在列上提供一个非复合索引,以最快地减少您的结果集(高基数)。换句话说,如果您的表中只存储了两周的数据(14 个不同的日期)但有 400 个不同的商店,那么您应该在senderShop_id 上建立一个索引,并确保您的统计数据是最新的。

这应该会导致 DBMS 执行引擎使用该键减少结果集,以便后续操作更快。

deliveryDate,senderShop_id,... 上的复合索引将无法使用 senderShop_id 来缩减结果,因为键排序将是 senderShop_id deliveryDate

【讨论】:

    猜你喜欢
    • 2017-10-04
    • 2015-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-01
    • 1970-01-01
    • 2012-03-31
    相关资源
    最近更新 更多