在未索引的 table 上使用 WHERE 子句进行 MySQL 查询 select 的最快方法

Fastest way to do MySQL query select with WHERE clauses on an unindexed table

我有一个非常大的未编入索引的 table,名为 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 和一个日期,将搜索该日期前一周的行和 return 包含“?kw=”的最近行每个IP。所以我想要 DISTINCT 入口点,但只有最近的入口点。

我被这个卡住了,我知道这是一个相对简单的 INNER JOIN,但我不知道最快的方法。

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

来自 table

的行
SELECT ...
  FROM very_big_unindexed_table t

仅在过去一周内...

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

在入口点中包含“?kw=”

   AND t.entrypoint LIKE '%?kw=%'

只有每个 IP 的最新行。有几种方法可以解决这个问题。一个非常大的未索引 table 上的相关子查询将吃掉你的午餐和午餐盒。如果没有索引,就无法绕过 table 和 "Using filesort" 操作的完整扫描。

考虑到不幸的情况,我们最好的性能选择可能是尽可能地减少集合,然后执行排序,并避免任何连接操作(回到 table) 并避免相关子查询。

那么,让我们从这样的事情开始,到 return all 过去一周的行,入口点为 '?kw='。这将是 table 的完整扫描和排序操作...

         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 中的优化器(至少)非常有预测性table.

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

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

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

  • table 的完整扫描(没有办法解决)
  • 排序操作(同样,没有办法解决)
  • 具体化包含满足谓词的所有行的派生 table
  • 通过派生的 table 为每个 IP
  • 拉出 "latest" 行