Mysql选择查询性能变差


Mysql select query performance gets bad

我得到了一个mysql查询,它选择了一天中每小时的所有点击。这个查询运行良好,直到我们的数据库中有很多点击条目。现在它有时需要几秒钟(最多9!)来请求数据。。。

查询是:

SELECT h.clickHour, COUNT(clicktime) AS c
      FROM ( SELECT 0 AS clickHour
             UNION ALL SELECT 1
             UNION ALL SELECT 2
             UNION ALL SELECT 3
             UNION ALL SELECT 4
             UNION ALL SELECT 5
             UNION ALL SELECT 6
             UNION ALL SELECT 7
             UNION ALL SELECT 8
             UNION ALL SELECT 9
             UNION ALL SELECT 10
             UNION ALL SELECT 11
             UNION ALL SELECT 12
             UNION ALL SELECT 13
             UNION ALL SELECT 14
             UNION ALL SELECT 15
             UNION ALL SELECT 16
             UNION ALL SELECT 17
             UNION ALL SELECT 18
             UNION ALL SELECT 19
             UNION ALL SELECT 20
             UNION ALL SELECT 21
             UNION ALL SELECT 22
             UNION ALL SELECT 23 ) AS h
    INNER JOIN links l ON l.user_id = 1
    LEFT OUTER
      JOIN clicks
        ON EXTRACT(HOUR FROM clicks.clicktime) = h.clickHour
          AND DATE(clicks.clicktime) = '2014-09-21'
          AND clicks.link_id = l.id
    GROUP
        BY h.clickHour

我得到了这些工会,因为我需要点击每小时,也需要空小时。。。请帮忙!

好的,我们讨论的是0到几千行的表点击。点击时间被保存为时间戳,每次点击都有一个唯一的id。我看到联合的事情很糟糕,我必须改变它。

我现在尝试的是选择一天中按小时(点击时间)分组的所有点击:但当我这样做的时候,我得到了太多像10x这样的结果,那么它应该是。

我会这样重写查询:

SELECT h.clickHour
     , IFNULL(d.clickCount,0) AS c
  FROM ( SELECT 0 AS clickHour UNION ALL SELECT  1 UNION ALL SELECT  2
           UNION ALL SELECT  3 UNION ALL SELECT  4 UNION ALL SELECT  5
           UNION ALL SELECT  6 UNION ALL SELECT  7 UNION ALL SELECT  8
           UNION ALL SELECT  9 UNION ALL SELECT 10 UNION ALL SELECT 11
           UNION ALL SELECT 12 UNION ALL SELECT 13 UNION ALL SELECT 14
           UNION ALL SELECT 15 UNION ALL SELECT 16 UNION ALL SELECT 17
           UNION ALL SELECT 18 UNION ALL SELECT 19 UNION ALL SELECT 20
           UNION ALL SELECT 21 UNION ALL SELECT 22 UNION ALL SELECT 23 
       ) h
  LEFT
  JOIN ( SELECT EXTRACT(HOUR FROM c.clicktime) AS clickHour
              , SUM(1) AS clickCount
           FROM clicks c
           JOIN links l
             ON l.user_id = 1
            AND l.id = c.link_id
          WHERE c.clicktime >= '2014-09-21'
            AND c.clicktime <  '2014-09-21' + INTERVAL 1 DAY 
          GROUP BY EXTRACT(HOUR FROM c.clicktime)
       ) d
    ON d.clickHour = h.clickHour

这里的方法是让内联视图查询d最多返回24行。这将通过clicks表来获取计数。我们将把连接操作推迟到固定的24行集合,直到我们计算完每小时计数之后。(h的联接只是为了获得返回的计数为零的行,否则这些行将只是"丢失"的行。)

您可以测试内联视图查询d的性能,对于整个查询,我怀疑不会有太大差异。实现内联视图h的成本并没有那么高(有一些开销,但很可能会使用内存存储引擎;它足够小,应该是简单的整数数据类型。)而且,即使没有任何可用的索引,24行到24行的连接操作也不会那么贵。

我怀疑大部分时间将用于具体化派生表d

我们想要一个前导列为clickDate的索引,这样我们就可以使用更高效的索引范围扫描操作,以避免对表中每个翻转行的表达式求值。

我将这个谓词DATE(clickTime) = '2014-09-21'更改为引用裸列的谓词,这使MySQL能够考虑对clickTime列进行有效的范围扫描操作(以快速消除大量行),而不是要求MySQL对表中的每一个翻转行都评估一个函数。

通过使clickslinks表上的覆盖索引可用,可以获得一些性能增益(这样就可以从索引中满足查询,而无需访问底层表中的页面。)

点击量表上的最低值:

ON clicks (clickTime, link_id)

如果idlinks表上是唯一的(或主键),则此索引可能不会带来任何性能优势:

ON links (id, user_id)

如果使用了覆盖索引,EXPLAIN输出应该显示"使用索引"。

我看不出有什么办法可以绕过"使用文件排序"操作,除非在clicks表中添加一列,存储截断为小时的clickTime。有了这样的列和适当的索引,我们就可以使用索引优化GROUP BY操作,从而避免"使用文件排序"操作。

你索引了吗?

点击表:点击时间,link_id

链接表:id,user_id