我有一个表以键值对格式存储动态用户数据。像这样:
UserId | Key | Value
---------------------------------
1 | gender | male
1 | country | Australia
2 | gender | male
2 | country | US
3 | gender | female
3 | country | Spain
现在,我需要选择具有特定参数的用户,例如:性别为“男性”,“国家/地区”为“美国”。或者更一般:
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过滤器适用于值更均匀和隔离的过滤器,我将获得最佳结果。
例如,“性别”可以有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.
结论:
在这种情况下,{p>INTERSECT
稍快一点EXISTS
。 INNER JOIN
选项比较慢。
答案 0 :(得分:3)
"什么条款最好放在第一个"
优化器完全适合您。查询不按写入方式进行评估。 EXISTS
被转换为连接并经历通常的连接重新排序优化。正在使用统计数据来推动这一进程。它并不完美,但通常都很好。
使用OPTION(RECOMPILE)获取针对您正在使用的特定搜索参数进行调整的计划。
select UserID from T where Condition1
intersect select UserID from T where Condition2
intersect select UserID from T where Condition3