【问题标题】:Optimize group by used along with where condition in mysql使用mysql中的where条件优化group by
【发布时间】:2014-02-04 18:03:03
【问题描述】:

我有一个大约 800 万行和 35 列的表(总体大小为 1G)。这用于涉及多级group by 条件的报告。这是一个这样的查询。

explain select min(a), max(a), avg(a), sum(b) from test where (c=2 or c=20 or c=18 or c=21 or c=12) and d>='2013-01-01' and d <= '2013-12-01' group by c,e;

*************************** 1. row ***************************
       id: 1
select_type: SIMPLE
    table: test
     type: range
possible_keys: PRIMARY
      key: PRIMARY
  key_len: 7
      ref: NULL
     rows: 154911
    Extra: Using where; Using temporary; Using filesort
1 row in set (0.00 sec)

这需要大约 1.8 秒来执行。主键在c,d 上,用于评估 where 子句。具有相同 where 条件且没有 group by 的 count(*) 查询返回大约 150000 行。所以在实际查询中扫描的行也是可以的。但是,没有一个索引被用于对结果进行分组。我尝试将索引放在cc,e 上。

我的问题是,一旦应用了条件并且结果集在 tmp 表中,是否可以使用另一个索引进行排序/分组。

我已为tmp_table_size 分配了足够的内存。因此,tmp 表肯定不会磁盘。该表正在使用MyISAM

【问题讨论】:

  • FWIW,我更喜欢 \G 来解释
  • 您的查询引用了一个未定义的表别名d (d.effective_date)。
  • @GordonLinoff : sry man.. 生效日期仍然是一个错误......我已经编辑了查询以使其更有意义。
  • 这个查询返回多少行?
  • 请注意您对日期的查询。如果您打算做一整年(截至 2013 年 12 月 31 日),并且您的交易记录在日期/时间字段中有 TIME 部分,那么这将不包括 2013 年 12 月 31 日 3:15 的所有 12 月 31 日数据早上大于 2013 年 12 月 31 日凌晨 12:00。您应该考虑少于 2014 年 1 月 1 日,因此它会一直持续到 12 月 31 日晚上 11:59:59。

标签: mysql sql database myisam database-optimization


【解决方案1】:

如果您使用 (c, d , e , a , b) 创建索引,那么性能会更快。这将是一个覆盖索引,不会像现在那样进行表扫描。

另外,我只是好奇,你能给我一些关于你正在使用的 Effective_month 功能的指点吗?

另外,一个重要的事情是索引大小。每个表的最大索引数和最大索引长度由每个存储引擎定义。你可以阅读更多关于它的信息here。在您的情况下,这不是问题,因为您正在处理我假设日期和数字。只是插入会慢一些。

【讨论】:

  • 我不想输入实际的查询.. 有效日期仍然存在错误.. 请现在查看查询.. 在 (c, d , c , e , a ,b)我认为您的建议会变成什么...但是我们不能将同一列多次放入索引中...可以吗?
  • 现在请看。我已经修改了答案。
  • 感谢您的建议.. 我试过这个.. 但性能恶化,扫描的行数激增至 450000... 在任何情况下,这个查询不是我唯一的用例,我没有我可以为我的每个用例创建太多的复合索引
  • 你可以在运行这个查询后运行优化表 吗?看看表演然后请让我知道。
  • 试过了..没有变化...我的表的行根本没有更新..我们会定期截断并再次插入所有行..所以优化表不应该有给定性能提升
【解决方案2】:

在任何 SQL 中,无论出于何种原因,如果只对一个表执行多次扫描,我们可以为其中任何一个使用一个索引,但不能同时为两个。

EX:您的查询需要

  1. 一次扫描处理 where 子句数据。(INDEX1:c 上的索引,d 很有用)
  2. 一次扫描以按操作对结果集进行排序。(INDEX2:c 上的索引,e 很有用)

如果结果集中的行数更多,最好添加 INDEX2 以便排序更快。 如果结果集中的行数较少,最好添加 INDEX1,以便快速处理 where 子句。

【讨论】:

    【解决方案3】:

    覆盖索引可能会有所帮助。假设这是您的查询:

    select min(a), max(a), avg(a), sum(b)
    from test
    where (c=2 or c=20 or c=18 or c=21 or c=12) and
          d >= '2013-01-01' and d <= '2013-12-01'
    group by c, e;
    

    覆盖索引为test(c, d, e, a, b)

    然而,在 MySQL 聚合中摆脱文件排序非常困难。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-08-30
      • 1970-01-01
      • 1970-01-01
      • 2015-11-10
      • 1970-01-01
      • 1970-01-01
      • 2014-05-04
      相关资源
      最近更新 更多