MySQL 的 LIMIT 和 Teradata 的 TOP 在对非索引变量进行调节时的区别

Difference between MySQL's LIMIT and Teradata's TOP when conditioning on non-indexed variables

今天上班,我尝试在 Teradata 中执行以下命令但失败了:

SELECT TOP 10 * FROM tab WHERE col <> 1

正如一位同事后来向我解释的那样,Teradata 首先 运行 在整个 table 上设置 WHERE 条件(太大了),然后再选择 TOP 10。据我的同事说,如果 col 被编入索引,情况会有所不同。

现在我想知道 MySQL 是否真的在做同样的事情;可能我只是从来没有足够地突破界限。是否

SELECT * FROM tab WHERE col != 1 LIMIT 10

在返回前 10 个之前 运行 整个 table 的 col != 1 条件(如果这改变了答案,让 col 不被索引)?

提前致谢。

首先,你不应该使用 LIMIT / TOP 除非你也使用 ORDER BY,如果你对 return 到底是什么感兴趣(除了有这么多记录的事实完全没有)。

话虽如此,MySQL 将 不会 扫描整个 table(如果 tab 是 table)或在 return 对 LIMIT 记录进行索引之前:它将 return 记录扫描和过滤它们,并且一旦有足够的记录就会停止。

但是,如果 tab 不是 table,而是一个视图,并且如果它包含嵌套查询,或 GROUP BY 条件或类似的东西,MySQL 可能需要在过滤和限制之前扫描所有底层 tables。

在像 Teradata 这样的大型并行 DBMS 上,情况有所不同。一个系统可能包含数百个物理服务器和数千个 AMP(Teradata "instances"),并且一个 table 分布在系统中的所有 AMP 中,正如@Shadow 在评论中已经提到的那样。

现在,当您提交带有任何 WHERE 条件(或连接或聚合)的 TOP 时,系统实际上会首先创建一个包含所有过滤行的中间假脱机,然后应用顶级逻辑.您可以很容易地看到,当您 EXPLAIN 查询时,最后一步包括一个 STAT FUNCTION ... 用于检索前 10 行.

您这样做可能是为了快速查看数据,因此您可以删除 WHERE-条件,然后它真的很快,因为单个 AMP 将只读取其第一个数据块。如果你真的需要过滤后的数据,你可以使用这个:

SELECT TOP 10 *
FROM 
 (
   SELECT TOP 1000 *  
   FROM tab 
 ) AS dt
WHERE col <> 1

在 Derived Table 中使用 TOP n,它足够大 return 至少 10 行匹配外部条件。