Mysql多重索引对单个查询不起作用(Group By + RangeWhere条件)

标签 mysql sql indexing

我有一个如下查询:

Select 
sum(r.impressions) as impressions from keyword_report r 
where r.org_id = 1
and r.report_date between '2019-09-01' and '2019-09-10'
group by r.country, r.keyword_id;

我在 keywords_report 上有 2 个索引;

index1: (org_id, report_date)
index2: (country, keyword_id)

解释format=json结果:

{
  "query_block": {
    "select_id": 1,
    "cost_info": {
      "query_cost": "138210.60"
    },
    "grouping_operation": {
      "using_temporary_table": true,
      "using_filesort": false,
      "table": {
        "table_name": "r",
        "access_type": "ref",
        "possible_keys": [
          "index1",
          "index2"
        ],
        "key": "index1",
        "used_key_parts": [
          "org_id",
          "report_date"
        ],
        "key_length": "11",
        "ref": [
          "const",
          "const"
        ],
        "rows_examined_per_scan": 125646,
        "rows_produced_per_join": 125646,
        "filtered": "100.00",
        "index_condition": "(`r`.`report_date` between '2019-09-01' and '2019-09-10')",
        "cost_info": {
          "read_cost": "125646.00",
          "eval_cost": "12564.60",
          "prefix_cost": "138210.60",
          "data_read_per_join": "162M"
        },
        "used_columns": [
          "org_id",
          "keyword_id",
          "impressions",
          "report_date",
          "country"
        ]
      }
    }
  }
}

表中大约有;

  • 1000 个不同的 org_id,
  • 500 个不同的 report_date,
  • 30 个不同的国家/地区,
  • 1000 万keyword_id。

我无法理解这里的两件事。

  1. 为什么使用临时?

  2. 为什么多个索引不起作用?

那么我该如何改进呢?

最佳答案

以下 JSON 输出似乎表明您的 index1 索引正在被使用:

"used_key_parts": [
  "org_id",
  "report_date"
]

可以在 WHERE 子句中使用此索引来过滤掉不匹配的记录。此后,MySQL 仍然必须执行 GROUP BY 聚合,其中包括对 impressions 列的求和。请注意,索引对于聚合并没有太大帮助,因为根据定义,数据库必须接触每个组中的每个记录才能计算总和。虽然大多数时候数据库甚至不会选择在同一个表上使用两个不同的索引(但这是可能的),但在这种情况下,第二个 index2 索引在这里没有多大帮助,因为您的聚合的性质。

为了给出一个可以使用单个索引来涵盖查询的所有步骤的示例,请考虑以下内容:

SELECT
    r.country,
    MAX(r.impressions) AS max_impressions
FROM keyword_report r 
WHERE
    r.org_id = 1 AND
    r.report_date BETWEEN '2019-09-10' AND '2019-09-10'
GROUP BY
    r.country;

现在,如果您定义了以下索引:

(org_id, report_date, country, impressions)

那么MySQL可能会选择使用它。它之所以有效,是因为在过滤掉 WHERE 子句中的记录后,可以轻松找到每个国家/地区的 impressions 最大值。

关于Mysql多重索引对单个查询不起作用(Group By + RangeWhere条件),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58049840/

相关文章:

MYSQL INSERT 基于 3 列的值

oracle - 对只有 5 个不同值的列进行索引 - 值得吗?

mysql - 与 GROUP BY 一起执行 JOINS 和 CONDITIONS 时重复 COUNT

sql - 如何将 String 值转换(或强制转换)为 Integer 值?

sql - 在 BigQuery 中使用所有字符串列的限制

sql - 使用 SQL 定义一对多关系

python - 无法转换 Pandas 数据帧时间戳

sql - SQL中簇索引和非簇索引的区别

java - Hibernate Multi-Tenancy 命名策略

php - 动态准备语句,PHP