这是我的要求:
SELECT TOP 10 * FROM BigTable WHERE Value <> 2;
BigTable有点特别,因为Value
列包含每行的相同值:2
。在实际情况中,可能有一些行具有不同的值,但不是很多。我确实需要找到这些流氓行。但是,我不知道在设计时哪个值(2只是一个例子)(但我知道在查询时)。
请求很慢(大约5分钟); BigTable包含1000万行。
所以我在Value
列上添加了一个索引,该列的类型为smallint。 10分钟后,索引建成了,我再次运行了请求。它仍然很慢。
这个问题可以在这里复制:http://sqlfiddle.com/#!6/6ce0f/1
此时,我的猜测是SQL Server无法使用索引进行<>
运算符的查询,但我不确定为什么?例如,此其他查询只需2秒:SELECT TOP 10 Value FROM BigTable GROUP BY Value
(并返回单行,其值为2
,如预期的那样)。
我正在考虑拆分成多个查询:一个用于获取不同值的列表,另一个用于获取所有流氓行,例如SELECT TOP 10 * FROM BigTable WHERE Value = x
等(所有值都不是2),但是有更好的解决方案吗?
编辑:
此查询的想法是查找在更新大多数行的进程之后尚未更新的行。基本上,我正在与另一个数据源同步。每次运行此过程时,我都会增加该值,并使用新值(以及更新的数据)更新每一行。在该过程结束时,我可以检查哪些行具有旧值,并删除它们。这个过程有点长,这就是为什么我不想先截断表并插入后,因为我需要先前的数据在这个流程执行期间保持可用。
索引是使用此请求创建的(由Entity Framework Core生成,但我手动进行查询测试):
CREATE NONCLUSTERED INDEX [IX_Value] ON [dbo].[BigTable]
(
[Value] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
编辑2:
以下是来自SSMS的估计查询计划(没有什么是最高机密,但由于我没有问我是否可以透露项目的内容,我已经模糊了数据库名称;在这些屏幕截图中还有表格和列名称是真实的)
您可以看到它根本不使用IX_Establishments_UpdateTag
(索引扫描位于主键上)。执行时间:5分18秒(在这次运行中,我有一行Value/UpdateTag
不是2)
此处使用IX_Establishments_UpdateTag
索引。执行时间小于1秒(SSMS报告0秒)。
答案 0 :(得分:1)
SQL可以使用<>
查询的索引。 “可以”并不意味着它会,它只意味着优化器会考虑它们。
当OR
存在时,SQL通常会出现问题 - 这些通常(可能总是?)会导致全表扫描。 Value IN (1,2,3)
必须“翻译”为“值= 1或值= 2或值= 3”。
Value < 2 OR Value > 2
对你我来说很明显,但优化器可能不够聪明,意识到这相当于Value <> 2
...所以它将它留作OR
,并且chugs和桌面扫描。
至于为什么Value <> 2
无法快速运行,它取决于您的数据。做一些猜测,而不是在这里进行必要的细节:
(可以通过运行
查看统计信息dbcc show_statistics (<TableName>, <IndexName>)
然而,理解统计数据完全是另一回事。如果你想走到这一步,请在网上查看相关文章和讨论。)
以上是很多“为什么”。如果没有深入研究数据,分析统计数据,并且这样做,我就没有现成的解决办法。作为一个虽然实验,如果我们将您的< OR >
查询转换为AND
查询怎么办?尝试
where not (Value >= 2 and Value <= 2)
看起来很傻,可能行不通,但值得一试,看看会发生什么。
答案 1 :(得分:0)
实际上有一个简单的解决方案似乎能够快速运行:
SELECT TOP 10 * FROM BigTable WHERE Value < 2
SELECT TOP 10 * FROM BigTable WHERE Value > 2
但请注意,在我的测试中,此查询速度很慢:
SELECT TOP 10 * FROM BigTable WHERE Value < 2 OR Value > 2
所以我需要执行两个不同的查询并在之后连接结果。我不知道是否有合理的解释。
答案 2 :(得分:0)
SQL Server可以使用索引进行<>
查询。
如下所示的简单查询
select top 100 empid,custid
from orderstest where orderid<>230
以下索引
create index nci on orderstest
(orderid)
include(custid,empid)
使sql server以下面的格式使用谓词
[1]寻找键[1]:结束:[PerformanceV3]。[dbo]。[orderstest]。 orderid&lt;标量算子((230)),
[2]寻找键[1]:开始:[PerformanceV3]。[dbo]。[orderstest]。 orderid&gt;标量运算符((230))
并且对于实际读取以检索行的行数
,估计也很好RunTimeCountersPerThread线程=&#34; 0&#34; ActualRows =&#34; 100&#34; ActualRowsRead =&#34; 100&#34;
所以我猜你的查询可能运行缓慢的原因可能是
2.我认为网络可能是一个瓶颈,取决于你如何呈现所有行
例如,
下面的查询返回所有行并在SSMS上显示
select empid,custid
from orderstest where orderid<>230
需要4秒,但在使用discard results set after execution
执行时会立即返回
其他一些原因可能是锁定,阻塞......您可以启用实际执行计划并在show plan xml中查找等待统计信息。以下我的查询是等待统计信息
<WaitStats>
<Wait WaitType="SOS_SCHEDULER_YIELD" WaitTimeMs="1" WaitCount="3" />
<Wait WaitType="ASYNC_NETWORK_IO" WaitTimeMs="4942" WaitCount="4389" />
</WaitStats>