SQL 基于值分布的服务器最优查询

SQL Server optimal query based on value distribution

我有一个 table 以键值对格式存储动态用户数据。像这样:

UserId | Key       | Value
---------------------------------
1      | gender    | male
1      | country   | Australia
2      | gender    | male
2      | country   | US
3      | gender    | female
3      | country   | Spain

现在,我需要 select 具有特定参数的用户,例如:性别是 'male' 并且国家是 'US'。或者更笼统:

key1=value1 AND key2=value2 AND key3=value3 AND ...

为此,我发现最快的方法是执行以下操作:

WHERE key=(key1) 
AND   value=value1
AND   EXISTS(SELECT 1
             FROM (...)
             WHERE key=key2
             AND   value=value2)
AND   EXISTS(SELECT 1
             FROM (...)
             WHERE key=key3
             AND   value=value3)
AND   EXISTS(...)

在那种情况下,如果第一个 WHERE 过滤器适用于值更均匀和分离的过滤器,我将获得最佳结果。

例如,'gender' 可以有 99% 的男性和 1% 的女性,国家可以将整个人口划分为 100 个相似的部分。在那种情况下,我需要先按国家/地区过滤并使用 EXIST 作为性别条件。

问题: 在 SQL Server 2008 R2 中有没有什么方法可以获取索引统计信息以找到最好先放置哪个子句(基本上不在 EXISTS 中)?

替代问题:我认为这是最好的方法,但重写该查询以使其始终最优的方法也可以是解决方案。

解决方案信息:

正确的解决方案是下面@usr 解释的解决方案(使用 INTERSECT)。实际上,我似乎做错了什么,EXISTS 也被引擎正确解析了。为了提供更多信息,我分享了 IO 和 TIME 统计数据以及测试选项的执行计划:

使用INTERSECT:

Table 'PERFTEST'. Scan count 2, logical reads 113, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 0 ms,  elapsed time = 2 ms.

使用EXISTS

Table 'PERFTEST'. Scan count 2, logical reads 113, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 0 ms,  elapsed time = 3 ms.

(注意额外的 Stream Aggregate 步骤)

使用INNER JOIN:

Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'PERFTEST'. Scan count 2, logical reads 113, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 31 ms,  elapsed time = 25 ms.

结论:

在这种情况下,

INTERSECTEXISTS 稍微快一些。 INNER JOIN 选项要慢得多。

"what clause is better to put first"

优化器正是为您做的。查询不会按书面形式进行评估。 EXISTS 被转换为连接并进行通常的连接重新排序优化。正在使用统计数据来推动该过程。它并不完美,但通常很好。

使用选项(重新编译)获取针对您正在使用的特定搜索参数进行调整的计划。


select UserID from T where Condition1
intersect select UserID from T where Condition2
intersect select UserID from T where Condition3