【问题标题】:MYSQL - How to add index for group by / order by / sum / with whereMYSQL - 如何为 group by / order by / sum / with where 添加索引
【发布时间】:2016-05-10 07:01:17
【问题描述】:

我正在处理一个有 40K 行的 mysql 表。当前执行时间大约是 2 秒,表被索引。有人可以指导我如何更好地优化这个查询和表吗?以及如何摆脱“使用位置;使用临时;使用文件排序”??。任何帮助表示赞赏。

goup by 用于以下情况...

  1. LS_CHG_DTE_OCR
  2. LS_CHG_DTE_OCR/RES_STATE_HSE
  3. LS_CHG_DTE_OCR/RES_STATE_HSE/RES_CITY_HSE
  4. LS_CHG_DTE_OCR/RES_STATE_HSE/RES_CITY_HSE/POSTAL_CDE_HSE

提前致谢

SELECT DATE_FORMAT(`LS_CHG_DTE_OCR`, '%Y-%b') AS fmt_date, 
    SUM(IF(`TYPE`='Connect',COUNT_SUBS,0)) AS connects, 
    SUM(IF(`TYPE`='Disconnect',COUNT_SUBS,0)) AS disconnects,
    SUM(IF(`TYPE`='Connect',ROUND(REV,2),0)) AS REV, 
    SUM(IF(`TYPE`='Upgrade',COUNT_SUBS,0)) AS upgrades, 
    SUM(IF(`TYPE`='Downgrade',COUNT_SUBS,0)) AS downgrades,
    SUM(IF(`TYPE`='Upgrade',ROUND(REV,2),0)) AS upgradeRev FROM `hsd`
    WHERE LS_CHG_DTE_OCR!='' GROUP BY MONTH(LS_CHG_DTE_OCR) ORDER BY LS_CHG_DTE_OCR ASC



CREATE TABLE `hsd` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `SYS_OCR` varchar(255) DEFAULT NULL,
  `PRIN_OCR` varchar(255) DEFAULT NULL,
  `SERV_CDE_OHI` varchar(255) DEFAULT NULL,
  `DSC_CDE_OHI` varchar(255) DEFAULT NULL,
  `LS_CHG_DTE_OCR` datetime DEFAULT NULL,
  `SALESREP_OCR` varchar(255) DEFAULT NULL,
  `CHANNEL` varchar(255) DEFAULT NULL,
  `CUST_TYPE` varchar(255) DEFAULT NULL,
  `LINE_BUS` varchar(255) DEFAULT NULL,
  `ADDR1_HSE` varchar(255) DEFAULT NULL,
  `RES_CITY_HSE` varchar(255) DEFAULT NULL,
  `RES_STATE_HSE` varchar(255) DEFAULT NULL,
  `POSTAL_CDE_HSE` varchar(255) DEFAULT NULL,
  `ZIP` varchar(100) DEFAULT NULL,
  `COUNT_SUBS` double DEFAULT NULL,
  `REV` double DEFAULT NULL,
  `TYPE` varchar(255) DEFAULT NULL,
  `lat` varchar(100) DEFAULT NULL,
  `long` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx` (`LS_CHG_DTE_OCR`,`CHANNEL`,`CUST_TYPE`,`LINE_BUS`,`RES_CITY_HSE`,`RES_STATE_HSE`,`POSTAL_CDE_HSE`,`ZIP`,`COUNT_SUBS`,`TYPE`)
) ENGINE=InnoDB AUTO_INCREMENT=402342 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC


Using where; Using temporary; Using filesort[enter image description here][1]

【问题讨论】:

    标签: mysql optimization indexing


    【解决方案1】:

    您应用的唯一条件是 LS_CHG_DTE_OCR != ""。除此之外,由于聚合,您正在执行全表扫描。索引明智的,你不能在这里做很多事情。

    我遇到了同样的问题。我已经完全优化了我的查询(我有连接和更多条件),但表不断增长,查询时间也随之增长。最后我决定将数据镜像到 ElasticSearch。在我的例子中,它将查询时间减少到大约 1/20 到 1/100(对于不同的查询)。

    【讨论】:

    • 感谢 TehSphinX,但 LS_CHG_DTE_OCR != "" 不是唯一的条件。 CHANNEL、LINE_BUS、CUST_TYPE、RES_CITY_HSE、RES_STATE_HSE、ZIP 列也会出现条件。不过我稍后会索引它。
    • 另外,我还有另一种方式来重写这个查询??
    • 目前我看不到重写查询的方法。是您在查询中使用的索引吗?我试过了,它看起来好像没有使用它,但可能是因为我的表是空的 mysql 偷工减料。
    • 是的 TehSphinX。由于您有任何线索可以摆脱“使用位置;使用临时;使用文件或。”
    • “使用位置”无法删除。缺少的是“使用索引”(在我的测试中)。据我所知,这只适用于没有聚合的情况。 “使用临时”来自您对“Month(...)”等函数的使用。 “使用文件排序”也是如此。因此,除非您可以在没有查询所做的很多事情的情况下生活,否则您无法删除它们。问题是没有“使用索引”——至少在我的测试中我没有得到它,除非我删除所有聚合列。
    【解决方案2】:

    SELECT 唯一可能的索引是INDEX(LS_CHG_DTE_OCR)。但它不太可能被使用。

    1. 执行WHERE——如果有很多''值,那么索引可以用于过滤。
    2. GROUP BY MONTH(...) -- 您可能会折叠多年的同一个月。优化器无法判断,因此它会继续使用索引。
    3. ORDER BY LS_CHG_DTE_OCR -- 这是在GROUP BY 之后完成的;在收集数据之前无法执行ORDER BY——对于任何索引来说都太迟了。但是,如果将多年叠加在一起,您可能会得到一些奇怪的结果。通过使ORDER BYGROUP BY 相同来解决它。这也将防止由于GROUP BYORDER BY 不同而导致的额外排序。

    是的,如果您添加的 idx 具有 所有 SELECT 中的列,那么它就是一个“覆盖索引”。但由于上面的 cmets,它无济于事。 “使用索引”不会有太大帮助。

    GROUP BY LS_CHG_DTE_OCR/RES_STATE_HSE -- 嗯?将DATETIME 除以VARCHAR?这听起来像是一场灾难。

    随着时间的推移,这张桌子会变得更大,对吗?考虑使用month 构建和维护汇总表作为PRIMARY KEY 的一部分。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-30
      • 2013-01-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多