MySQL在查询中显示使用了索引

时间:2014-09-10 14:18:26

标签: mysql database indexing query-optimization explain

例如我创建了3个索引:

  • click_date - transaction表,daily_metric
  • order_date - transaction table

我想检查我的查询是否使用索引,我使用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表的index_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

1 个答案:

答案 0 :(得分:1)

虽然我无法解释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

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

澄清。

在构建&#34;点击&#34;的预聚合查询时,与您一样和&#34;订单&#34;,&#34; AllPartners&#34;是您感兴趣的日期范围内选择不同的合作伙伴和日期的ALIAS结果。其中的结果列是&#34; partner_id&#34;和&#34; the_date&#34;对应于您的下一个查询。因此,这是加入&#34;点击&#34;的总和的基础。和&#34;命令&#34;。因此,由于我在别名&#34; AllParnters&#34;中有这两列,我只是抓取了字段列表的那些,因为它们被LEFT-JOIN到其他别名,并且可能不存在于任何一个/或相应的其他别名中。