Mysql多索引不';不适用于单个查询(分组依据&x2B;范围条件)
我有一个问题如下:Mysql多索引不';不适用于单个查询(分组依据&x2B;范围条件),mysql,sql,indexing,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; 我有两个关于关键字报告的索引 index1: (org_id, report_date) index2: (country, ke
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;
我有两个关于关键字报告的索引
index1: (org_id, report_date)
index2: (country, keyword_id)
解释格式=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个不同的组织id
- 500个不同的报告日期
- 30个不同的国家
- 1000万美元
因此,如何改进它?以下JSON输出似乎表明正在使用您的
index1
索引:
"used_key_parts": [
"org_id",
"report_date"
]
此索引可在WHERE
子句中用于筛选不匹配的记录。在此之后,MySQL仍然必须执行一个groupby
聚合,其中包括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很少一次使用多个索引,除非在使用或
条件等时有可能出现索引合并
。在这种特殊情况下,第一优先级是其中
条件,这就是它使用index1
的原因,因为它可以通过使用索引将pin指向要查看的特定行来减少数据查找。此外,从逻辑上讲,其中
发生在分组依据之前,它还有助于减少要聚合的数据(而不是遍历整个表)
此外,没有其他索引建议会起作用,因为MySQL将在report\u date
遇到范围条件时停止
为什么要用临时的
因为,您使用的是分组依据
——查询将首先将所有数据提取到一个临时表中(同样,您的索引没有覆盖),并且一旦该过程完成,它将相应地执行聚合
还解释了:
使用临时(JSON属性:使用临时表)
为了解决这个查询,MySQL需要创建一个临时表来保存
结果呢。如果查询包含GROUP BY和,则通常会发生这种情况
列出不同列的ORDER BY子句
对于此查询:
select sum(r.impressions) as impressions, r.country, r.keyword_id
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;
只使用一个索引。您可以尝试索引关键字报告(组织id、报告日期、国家、关键字id、印象)
。这涵盖了查询,意味着可以使用所有列。然而,这种分类仍然是必要的
在查询的原始版本中,有两个操作数在
之间使用相同的值。我认为MySQL不够聪明,无法识别这两个操作数是相同的,因此它相当于=
。在这种情况下,您应该将查询表述为:
select sum(r.impressions) as impressions, r.country, r.keyword_id
from keyword_report r
where r.org_id = 1 and
r.report_date = '2019-09-10'
group by r.country, r.keyword_id;
然后MySQL可能会将索引用于分组依据
——MySQL可能会对使用分组依据
的索引很挑剔
我对这个版本的索引使用更有信心:
select ck.*,
(select sum(impressions)
from keyword_report r2
where r2.country = r.country and
r2.keyword_id = r.keyword_id and
r2.report_date = r.report_date
) as total_impressions
from (select distinct country, keyword_id
from keyword_report r
where r.org_id = 1 and
r.report_date = '2019-09-10'
) ck;
这将使用相同的索引
但是,对于实际范围,不能用这种方式重新表述查询。Gordon,报告日期应为范围。请再次检查。MySQL将在
report\u date
遇到范围条件时停止。所以,索引建议不起作用。报告日期是范围,所以在报告日期之后,您的索引(组织id、报告日期、国家/地区、印象)不起作用?@Sha我建议该索引用于不同的查询,而不是您在问题中提出的查询。对于您所介绍的内容,index1
可能是您所能得到的最好结果。“我如何改进它?”-您希望改进什么?对你来说太慢了吗?有多少行与WHERE条件匹配?分组后你得到多少行?