执行MySQL查询的最快方法是在未编制索引的表上选择WHERE子句

时间:2016-04-19 22:34:14

标签: mysql select where

我有一个非常大的无索引表,称为table,其行如下:

IP              entrypoint              timestamp
171.128.123.179 /page-title/?kw=abc     2016-04-14 11:59:52
170.45.121.111  /another-page/?kw=123   2016-04-12 04:13:20
169.70.121.101  /a-third-page/          2016-05-12 09:43:30

我想做出最快的查询,给定30个IP和一个日期,将在该日期前一周搜索行,并返回包含每个IP“?kw =”的最新行。所以我想要DISTINCT入口点,但只需要最新入口点。

我对此感到困惑我知道这是一个相对简单的INNER JOIN,但我不知道最快的方法。

顺便说一下:我现在无法添加索引,因为它非常大并且在为网站提供服务的数据库上。我打算用索引表替换它,不用担心。

1 个答案:

答案 0 :(得分:0)

表中的行

SELECT ...
  FROM very_big_unindexed_table t

仅在过去一周内......

 WHERE t.timestamp >= NOW() + INTERVAL - 1 WEEK

在入口点

中包含'?kw ='
   AND t.entrypoint LIKE '%?kw=%'

每个IP只有最新一行。有几种方法可以解决这个问题。一张非常大的无索引表上的相关子查询将吃掉你的午餐和午餐盒。如果没有索引,就无法完全扫描表格和“使用文件排序”操作。

鉴于不幸的情况,我们对性能的最佳选择可能是尽可能减少集合,然后执行排序,并避免任何连接操作(返回到该表)并避免相关子查询

所以,让我们从这样的事情开始,在入口点以“?kw =”返回过去一周所有行的行。这将是对表的完全扫描,以及排序操作......

         SELECT t.ip
              , t.timestamp
              , t.entry_point
           FROM very_big_unindexed_table t
          WHERE t.timestamp >= NOW() + INTERVAL -1 WEEK
            AND t.entrypoint LIKE '%?kw=%'
          ORDER BY t.ip DESC, t.timestamp DESC

我们可以使用不受支持的技巧和用户定义的变量。 (MySQL参考手册特别警告不要使用这样的模式,因为行为是(正式)未定义。非正式地,MySQL 5.1和5.5中的优化器(至少)是非常可预测的。

如果过去一周的行数是整个表的重要子集,我认为这将与您将获得的一样好。如果有很多行满足谓词,那么这将创建一个相当大的中间结果集(派生表)。

SELECT q.ip
     , q.entrypoint
     , q.timestamp
  FROM (
         SELECT IF(t.ip = @prev_ip, 0, 1) AS new_ip
              , @prev_ip  := t.ip         AS ip
              , t.timestamp               AS timestamp
              , t.entrypoint              AS entrypoint
           FROM (SELECT @prev_ip := NULL) i
          CROSS
           JOIN very_big_unindexed_table t
          WHERE t.timestamp >= NOW() + INTERVAL -1 WEEK
            AND t.entrypoint LIKE '%?kw=%'
          ORDER BY t.ip DESC, t.timestamp DESC
       ) q
 WHERE q.new_ip

执行该查询将需要(根据需要花费的时间)

  • 对表格进行全面扫描(没有办法解决这个问题)
  • 排序操作(再次,没有办法解决)
  • 具体化包含满足谓词的所有行的派生表
  • 传递派生表以拉出每个IP的“最新”行