Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/78.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多索引不';不适用于单个查询(分组依据&x2B;范围条件)_Mysql_Sql_Indexing - Fatal编程技术网

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条件匹配?分组后你得到多少行?