Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MySql没有为几个查询选择正确的索引_Mysql_Sql_Query Optimization_Database Indexes - Fatal编程技术网

MySql没有为几个查询选择正确的索引

MySql没有为几个查询选择正确的索引,mysql,sql,query-optimization,database-indexes,Mysql,Sql,Query Optimization,Database Indexes,我在表上运行folling查询,在where条件下更改值,同时在一种情况下运行它使用一个索引,另一种情况下使用另一个(错误的??)索引 查询1的行数为402954,大约需要1.5秒 查询2的行数为52097大约需要35秒 查询1和查询2都是相同的,只是我在where条件中更改了值 问题1 EXPLAIN SELECT log_type,count(DISTINCT subscriber_id) AS distinct_count, count(subscriber_id)

我在表上运行folling查询,在where条件下更改值,同时在一种情况下运行它使用一个索引,另一种情况下使用另一个(错误的??)索引

查询1的行数为402954,大约需要1.5秒

查询2的行数为52097大约需要35秒

查询1和查询2都是相同的,只是我在where条件中更改了值

问题1

EXPLAIN SELECT 
     log_type,count(DISTINCT subscriber_id) AS distinct_count,
     count(subscriber_id) as total_count 
FROM campaign_logs 
WHERE 
    domain = 'xxx' AND 
    campaign_id='123' AND 
    log_type IN ('EMAIL_SENT', 'EMAIL_CLICKED', 'EMAIL_OPENED', 'UNSUBSCRIBED') AND 
    log_time BETWEEN 
       CONVERT_TZ('2015-02-12 00:00:00','+05:30','+00:00') AND
       CONVERT_TZ('2015-02-19 23:59:58','+05:30','+00:00') 
GROUP BY log_type;
解释上述问题

+----+-------------+---------------+-------+------------------------------------------------------------------------------------------------------+-----------------------------------------+---------+------+--------+-------------+
| id | select_type | table         | type  | possible_keys                                                                                        | key                                     | key_len | ref  | rows   | Extra       |
+----+-------------+---------------+-------+------------------------------------------------------------------------------------------------------+-----------------------------------------+---------+------+--------+-------------+
|  1 | SIMPLE      | campaign_logs | range | campaign_id_index,domain_index,log_type_index,log_time_index,campaignid_domain_logtype_logtime_index | campaignid_domain_logtype_logtime_index | 468     | NULL | 402954 | Using where |
+----+-------------+---------------+-------+------------------------------------------------------------------------------------------------------+-----------------------------------------+---------+------+--------+-------------+
+----+-------------+---------------+-------------+------------------------------------------------------------------------------------------------------+--------------------------------+---------+------+-------+------------------------------------------------------------------------------+
| id | select_type | table         | type        | possible_keys                                                                                        | key                            | key_len | ref  | rows  | Extra                                                                        |
+----+-------------+---------------+-------------+------------------------------------------------------------------------------------------------------+--------------------------------+---------+------+-------+------------------------------------------------------------------------------+
|  1 | SIMPLE      | campaign_logs | index_merge | campaign_id_index,domain_index,log_type_index,log_time_index,campaignid_domain_logtype_logtime_index | campaign_id_index,domain_index | 153,153 | NULL | 52097 | Using intersect(campaign_id_index,domain_index); Using where; Using filesort |
+----+-------------+---------------+-------------+------------------------------------------------------------------------------------------------------+--------------------------------+---------+------+-------+------------------------------------------------------------------------------+
问题2

EXPLAIN SELECT 
    log_type,count(DISTINCT subscriber_id) AS distinct_count,
    count(subscriber_id) as total_count 
FROM stats.campaign_logs 
WHERE 
    domain = 'yyy' AND 
    campaign_id='345' AND 
    log_type IN ('EMAIL_SENT', 'EMAIL_CLICKED', 'EMAIL_OPENED', 'UNSUBSCRIBED') AND 
    log_time BETWEEN 
         CONVERT_TZ('2014-02-05 00:00:00','+05:30','+00:00') AND
         CONVERT_TZ('2015-02-19 23:59:58','+05:30','+00:00') 
GROUP BY log_type;
解释上述问题

+----+-------------+---------------+-------+------------------------------------------------------------------------------------------------------+-----------------------------------------+---------+------+--------+-------------+
| id | select_type | table         | type  | possible_keys                                                                                        | key                                     | key_len | ref  | rows   | Extra       |
+----+-------------+---------------+-------+------------------------------------------------------------------------------------------------------+-----------------------------------------+---------+------+--------+-------------+
|  1 | SIMPLE      | campaign_logs | range | campaign_id_index,domain_index,log_type_index,log_time_index,campaignid_domain_logtype_logtime_index | campaignid_domain_logtype_logtime_index | 468     | NULL | 402954 | Using where |
+----+-------------+---------------+-------+------------------------------------------------------------------------------------------------------+-----------------------------------------+---------+------+--------+-------------+
+----+-------------+---------------+-------------+------------------------------------------------------------------------------------------------------+--------------------------------+---------+------+-------+------------------------------------------------------------------------------+
| id | select_type | table         | type        | possible_keys                                                                                        | key                            | key_len | ref  | rows  | Extra                                                                        |
+----+-------------+---------------+-------------+------------------------------------------------------------------------------------------------------+--------------------------------+---------+------+-------+------------------------------------------------------------------------------+
|  1 | SIMPLE      | campaign_logs | index_merge | campaign_id_index,domain_index,log_type_index,log_time_index,campaignid_domain_logtype_logtime_index | campaign_id_index,domain_index | 153,153 | NULL | 52097 | Using intersect(campaign_id_index,domain_index); Using where; Using filesort |
+----+-------------+---------------+-------------+------------------------------------------------------------------------------------------------------+--------------------------------+---------+------+-------+------------------------------------------------------------------------------+
查询1使用了正确的索引,因为我有复合索引

查询2正在使用索引合并,执行时间很长

为什么MySql对同一查询使用不同的索引


我知道我们可以在查询中提到使用索引,但是为什么MySql在这种情况下没有选择正确的索引呢??。我做错什么了吗?

不,你没有做错什么

正如Chipmonkey在评论中所说的,有时MySQL会因为过时的表统计信息而选择错误的执行计划。您可以通过执行
分析表格
来更新表格统计信息

不过,MySQL优化器并没有那么复杂。它发现,在这两种情况下,MySQL都必须访问二级索引,然后对聚集索引执行查找以获得实际的表数据,因此当它看到第二个查询通过使用两个单独的索引并合并它们而具有更好的选择性时,您不能因为猜测错误而过分责怪它

我猜如果你有一个覆盖索引,这样MySQL就可以只使用索引执行整个查询,那么它会倾向于使用该索引而不是执行合并

尝试将
subscriber\u id
添加到多列索引的末尾,以获得覆盖索引


否则,请使用
使用索引
强制索引
,因为这就是它们的用途。您比MySQL更了解数据。

不,您没有做错任何事情

正如Chipmonkey在评论中所说的,有时MySQL会因为过时的表统计信息而选择错误的执行计划。您可以通过执行
分析表格
来更新表格统计信息

不过,MySQL优化器并没有那么复杂。它发现,在这两种情况下,MySQL都必须访问二级索引,然后对聚集索引执行查找以获得实际的表数据,因此当它看到第二个查询通过使用两个单独的索引并合并它们而具有更好的选择性时,您不能因为猜测错误而过分责怪它

我猜如果你有一个覆盖索引,这样MySQL就可以只使用索引执行整个查询,那么它会倾向于使用该索引而不是执行合并

尝试将
subscriber\u id
添加到多列索引的末尾,以获得覆盖索引


否则,请使用
使用索引
强制索引
,因为这就是它们的用途。您比MySQL更了解数据。

我建议您尝试以下方法:

添加复合索引的这种排列

 (campaign_id,domain,log_time,log_type,subscriber_id)
更改查询以删除
WHERE log\u type IN()
条件,从而允许聚合函数使用它在
log\u time
上的范围扫描中找到的所有记录。在索引中包括
subscriber\u id
,应该允许直接从索引中满足整个查询。也就是说,这是一个覆盖指数

最后,您可以通过将整个查询包装到

  SELECT *
    FROM (/*the whole query*/) x
   WHERE log_type IN 
        ('EMAIL_SENT', 'EMAIL_CLICKED', 'EMAIL_OPENED', 'UNSUBSCRIBED')
   ORDER BY log_type
这将为您提供更好、更可预测的性能


(除非您想要的日志类型是记录的一小部分,否则请忽略此建议。)

我建议您尝试以下方法:

添加复合索引的这种排列

 (campaign_id,domain,log_time,log_type,subscriber_id)
更改查询以删除
WHERE log\u type IN()
条件,从而允许聚合函数使用它在
log\u time
上的范围扫描中找到的所有记录。在索引中包括
subscriber\u id
,应该允许直接从索引中满足整个查询。也就是说,这是一个覆盖指数

最后,您可以通过将整个查询包装到

  SELECT *
    FROM (/*the whole query*/) x
   WHERE log_type IN 
        ('EMAIL_SENT', 'EMAIL_CLICKED', 'EMAIL_OPENED', 'UNSUBSCRIBED')
   ORDER BY log_type
这将为您提供更好、更可预测的性能


(除非您想要的日志类型是记录的一小部分,在这种情况下,请忽略此建议。)

有时候,像这样糟糕的查询优化与糟糕的统计数据有关——可能会有很多问题,MySQL将其记录在此处:。考虑运行分析表来更新关于索引分布的统计信息,然后重新运行解释。有时这样的坏查询优化与坏的统计有关-有很多可以继续的,MySQL文档在这里:考虑运行分析表来更新索引分布的统计信息,然后重新运行解释。@亚当斯,谢谢您的评论,表有2500万+记录,它有8列,所以我的问题是在5列上有覆盖索引是安全的,我怀疑它会增加磁盘空间。它将增加磁盘空间(理想情况下是内存占用)。还有一个专栏是什么?这里还有一个专栏。这个问题是修辞性的。索引中已有4列。为什么现在要担心5列?@Adams,谢谢你的评论,这个表有2500多万条记录,它有8列,所以我的问题是在5列上有覆盖索引是否安全,我怀疑它会增加磁盘空间。是的,它会增加磁盘空间(理想情况下是内存占用)。还有一个专栏是什么?这里还有一个专栏。这个问题是修辞性的。索引中已有4列。为什么现在要担心5列?这是真的。MySQL只能对第一个范围内的搜索使用索引。删除日志类型sh的范围要求