MySQL显示查询中使用的索引

标签 mysql database indexing query-optimization explain

例如我创建了3个索引:

  • click_date - transaction 表、daily_metric
  • order_date - 交易

我想检查我的查询是否使用索引,我使用 EXPLAIN 函数并得到此结果:

+----+--------------+--------------+-------+---------------+------------+---------+------+--------+----------------------------------------------+
| id | select_type  | table        | type  | possible_keys | key        | key_len | ref  | rows   | Extra                                        |
+----+--------------+--------------+-------+---------------+------------+---------+------+--------+----------------------------------------------+
|  1 | PRIMARY      | <derived2>   | ALL   | NULL          | NULL       | NULL    | NULL |    668 | Using temporary; Using filesort              |
|  2 | DERIVED      | <derived3>   | ALL   | NULL          | NULL       | NULL    | NULL |    645 |                                              |
|  2 | DERIVED      | <derived4>   | ALL   | NULL          | NULL       | NULL    | NULL |    495 |                                              |
|  4 | DERIVED      | transaction  | ALL   | order_date    | NULL       | NULL    | NULL | 291257 | Using where; Using temporary; Using filesort |
|  3 | DERIVED      | daily_metric | range | click_date    | click_date | 3       | NULL | 812188 | Using where; Using temporary; Using filesort |
|  5 | UNION        | <derived7>   | ALL   | NULL          | NULL       | NULL    | NULL |    495 |                                              |
|  5 | UNION        | <derived6>   | ALL   | NULL          | NULL       | NULL    | NULL |    645 | Using where; Not exists                      |
|  7 | DERIVED      | transaction  | ALL   | order_date    | NULL       | NULL    | NULL | 291257 | Using where; Using temporary; Using filesort |
|  6 | DERIVED      | daily_metric | range | click_date    | click_date | 3       | NULL | 812188 | Using where; Using temporary; Using filesort |
| NULL | UNION RESULT | <union2,5>   | ALL   | NULL          | NULL       | NULL    | NULL |   NULL |                                              |
+----+--------------+--------------+-------+---------------+------------+---------+------+--------+----------------------------------------------+

EXPLAIN结果中我看到,交易表的索引order_date没有被使用,我的理解正确吗? daily_metric 表的索引 click_date 使用正确吗?

请告诉我如何从EXPLAIN结果中理解我创建的索引是否在查询中正确使用?

我的查询:

SELECT
    partner_id,
    the_date,
    SUM(clicks) as clicks,
    SUM(total_count) as total_count,
    SUM(count) as count,
    SUM(total_sum) as total_sum,
    SUM(received_sum) as received_sum,
    SUM(partner_fee) as partner_fee
    FROM (
        SELECT
            clicks.partner_id,
            clicks.click_date as the_date,
            clicks,
            orders.total_count,
            orders.count,
            orders.total_sum,
            orders.received_sum,
            orders.partner_fee
        FROM
            (SELECT
                partner_id, click_date, sum(clicks) as clicks
            FROM
                daily_metric WHERE DATE(click_date) BETWEEN '2013-04-01' AND '2013-04-30'
            GROUP BY partner_id , click_date) as clicks
            LEFT JOIN
            (SELECT
                partner_id,
                    DATE(order_date) as order_dates,
                    SUM(order_sum) as total_sum,
                    SUM(customer_paid_sum) as received_sum,
                    SUM(partner_fee) as partner_fee,
                    count(*) as total_count,
                    count(CASE
                        WHEN status = 1 THEN 1
                        ELSE NULL
                    END) as count
            FROM
                transaction WHERE DATE(order_date) BETWEEN '2013-04-01' AND '2013-04-30'
            GROUP BY DATE(order_date) , partner_id) as orders ON orders.partner_id = clicks.partner_id AND clicks.click_date = orders.order_dates
        UNION ALL SELECT
            orders.partner_id,
            orders.order_dates as the_date,
            clicks,
            orders.total_count,
            orders.count,
            orders.total_sum,
            orders.received_sum,
            orders.partner_fee
        FROM
            (SELECT
                partner_id, click_date, sum(clicks) as clicks
            FROM
                daily_metric  WHERE DATE(click_date) BETWEEN '2013-04-01' AND '2013-04-30'
            GROUP BY partner_id , click_date) as clicks
                RIGHT JOIN
            (SELECT
                partner_id,
                    DATE(order_date) as order_dates,
                    SUM(order_sum) as total_sum,
                    SUM(customer_paid_sum) as received_sum,
                    SUM(partner_fee) as partner_fee,
                    count(*) as total_count,
                    count(CASE
                        WHEN status = 1 THEN 1
                        ELSE NULL
                    END) as count
            FROM
                transaction  WHERE DATE(order_date) BETWEEN '2013-04-01' AND '2013-04-30'
            GROUP BY DATE(order_date) , partner_id) as orders ON orders.partner_id = clicks.partner_id AND clicks.click_date = orders.order_dates
        WHERE
            clicks.partner_id is NULL
        ORDER BY the_date DESC
        ) as t
        GROUP BY the_date ORDER BY the_date DESC LIMIT 50 OFFSET 0

最佳答案

虽然我无法解释 EXPLAIN 转储了什么,但我认为一定有一个更简单的解决方案来解决您所拥有的问题,并提出了以下解决方案。我建议使用以下索引来优化 WHERE 日期范围和按合作伙伴分组的现有查询。

此外,当您的查询在字段上使用 FUNCTION 时,它不会利用索引。例如您的 DATE(order_date) 和 DATE(click_date)。为了更好地使用索引,请限定完整的日期/时间,例如上午 12:00(上午)到晚上 11:59。我通常会通过

x >= someDate @12:00 and x < firstDayAfterRange.

在您的示例中是(请注意,小于 5 月 1 日,截至 4 月 30 日晚上 11:59:59)

click_date >= '2013-04-01' AND click_date < '2013-05-01'

Table         Index
transaction   (order_date, partner_id)
daily_metric  (click_date, partner_id)

现在,进行调整。由于您的点击表可能包含交易没有的条目,反之亦然,我会调整此查询以对所有可能的日期/合作伙伴进行预查询,然后左连接到相应的聚合查询,例如:

SELECT
      AllParnters.Partner_ID,
      AllParnters.the_Date,
      coalesce( clicks.clicks, 0 ) Clicks,
      coalesce( orders.total_count, 0 ) TotalCount,
      coalesce( orders.count, 0 ) OrderCount,
      coalesce( orders.total_sum, 0 ) OrderSum,
      coalesce( orders.received_sum, 0 ) ReceivedSum,
      coalesce( orders.partner_fee 0 ) PartnerFee
   from 
      ( select distinct
              dm.partner_id, 
              DATE( dm.click_date ) as the_Date
           FROM
              daily_metric dm
           WHERE 
              dm.click_date >= '2013-04-01' AND dm.click_date < '2013-05-01'
        UNION
        select
              t.partner_id,
              DATE(t.order_date) as the_Date
           FROM
              transaction t
           WHERE 
              t.order_date >= '2013-04-01' AND t.order_date < '2013-05-01' ) AllParnters

      LEFT JOIN
         ( SELECT
                 dm.partner_id, 
                 DATE( dm.click_date ) sumDate, 
                 sum( dm.clicks) as clicks
              FROM
                 daily_metric dm
              WHERE 
                 dm.click_date >= '2013-04-01' AND dm.click_date < '2013-05-01'
             GROUP BY 
                dm.partner_id, 
                DATE( dm.click_date )  ) as clicks
         ON AllPartners.partner_id = clicks.partner_id
         AND AllPartners.the_date = clicks.sumDate

      LEFT JOIN
      ( SELECT 
              t.partner_id,
              DATE(t.order_date) as sumDate,
              SUM(t.order_sum) as total_sum,
              SUM(t.customer_paid_sum) as received_sum,
              SUM(t.partner_fee) as partner_fee,
              count(*) as total_count,
              count(CASE WHEN t.status = 1 THEN 1 ELSE NULL END) as COUNT
           FROM
              transaction t
           WHERE 
              t.order_date >= '2013-04-01' AND t.order_date < '2013-05-01'
           GROUP BY 
              t.partner_id,
              DATE(t.order_date) ) as orders 
         ON AllPartners.partner_id = orders.partner_id
         AND AllPartners.the_date = orders.sumDate
   order by
      AllPartners.the_date DESC
   limit 50 offset 0

这样,第一个查询将很快在索引上从任一表中获取所有可能的组合。然后左连接最多将连接到每组一行。如果找到,则获取数字,如果没有,我将应用 COALESCE(),因此如果为 null,则默认为零。

澄清。

就像您在构建“点击”和“订单”的预聚合查询时一样,“AllPartners”是您感兴趣的日期范围内选择的不同合作伙伴和日期的 ALIAS 结果。结果列为与您的下一个查询相对应的“partner_id”和“the_date”在哪里。所以这是加入“点击”和“订单”聚合的基础。因此,由于我在别名“AllParnters”中拥有这两列,因此我只是将它们获取到字段列表,因为它们是左连接到其他别名的,并且可能不存在于相应的其他别名中。

关于MySQL显示查询中使用的索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25767826/

相关文章:

java - 摩尔斯电码转换器

sql-server-2005 - 如何解决 SQL Server 2005 中数据类型为 varchar(4096) 的列上的 900 键长度限制索引?

mysql - 是否可以更改数据库的 mysql 转储文件中的数据类型?

c# - 数据库中的 View 状态?方便吗?

database - 如何更改 SQL Server Compact Edition 表架构中的列顺序?

php - 获取返回的 PHP 结果数

mysql - 简单的多对多sql关系

mysql - SQL:所有的分隔符是什么?

MySQL多ID关系划分

php - Symfony sfDoctrineGuard 插入 SQL 错误 1005