我对以下内容感到困惑。我有一个大约1000万行的数据库,并且(在其他索引中)1列(campaignid_int)是一个索引。
现在我有700k行,其中campaignid确实是3835
对于所有这些行,connectionid是相同的。
我只是想找出这个连接。
use messaging_db;
SELECT TOP (1) connectionid
FROM outgoing_messages WITH (NOLOCK)
WHERE (campaignid_int = 3835)
现在这个查询需要大约30秒才能完成!
我(使用我的小数据库知识)会期望它会占用任何行,并返回给我那个connectionid
如果我为只有1个条目的广告系列测试同样的查询,那么它的速度非常快。因此索引有效。
我如何解决这个问题?为什么这不起作用?
编辑:
estimated execution plan:
select (0%) - top (0%) - clustered index scan (100%)
答案 0 :(得分:17)
由于统计信息,您应该明确要求优化器使用您创建的索引而不是群集索引。
SELECT TOP (1) connectionid
FROM outgoing_messages WITH (NOLOCK, index(idx_connectionid))
WHERE (campaignid_int = 3835)
我希望它能解决问题。
此致 恩里克
答案 1 :(得分:9)
我最近遇到了同样的问题,解决起来非常简单(至少在某些情况下)。
如果在索引的任何或部分列上添加ORDER BY
- 子句,则应解决该子句。这至少解决了我的问题。
答案 2 :(得分:4)
您没有在查询中指定ORDER BY
子句,因此没有指示优化器应该从中选择前1的排序顺序。 SQL Server不仅会采用随机行,它会按行排序并占据前1位,它可能会选择按次优的顺序排序。我建议您添加一个ORDER BY x
子句,其中x
作为该表上的聚簇键可能是最快的。
这可能无法解决你的问题 - 实际上我不确定我是否会从你给出的统计数据中得到它 - 但是(a)它不会受到伤害,并且(b)你将能够把它排除在外作为一个促成因素。
答案 3 :(得分:1)
如果campaignid_int
列未编入索引,请为其添加索引。这应该加快查询速度。现在我假设你需要进行全表扫描,以便在返回campaignid_int = 3835
行之前找到top(1)
的匹配项(在返回结果之前进行过滤)。
编辑:索引已经到位,但由于SQL Server执行了聚簇索引扫描,因此优化程序忽略了索引。这可能是由于(许多)重复的行具有相同的campaignid_int
值。您应该考虑采用不同的索引或在不同的列上进行查询以获得所需的connectionid
。
答案 4 :(得分:1)
索引可能没用,原因有两个:
否则,优化器决定它也可以使用PK /聚集索引来过滤campaignid_int并获取connectionid,以避免在当前索引的700k行上进行书签查找。
所以,我建议这个......
CREATE NONCLUSTERED INDEX IX_Foo ON MyTable (campaignid_int) INCLUDE (connectionid)
答案 5 :(得分:0)
您的查询无法正常工作,因为Sql Server会保留有关您的索引的统计信息,并且在此特定情况下知道有许多重复行的标识符为3835,因此它认为它更有意义做一个完整的索引(或表)扫描。当您测试只解析为一行的ID时,它会按预期使用索引,即执行索引查找(执行计划应验证此猜测)。
可能的解决方案?如果您有任何要编写的索引,请使索引合成,例如,用消息发送的日期(如果我理解你的情况正确)组成它,然后从列表中选择具有按日期排序的指定id的前1个条目。虽然我不确定这是否会更好(对于一个,复合索引占用更多空间) - 只是一个猜测。
编辑:我刚刚尝试了通过添加日期列来制作索引合成的建议。如果您这样做并在查询中指定order by date
,则会按预期执行索引搜索。
答案 6 :(得分:0)
这不能解答您的问题,但请尝试使用:
SET ROWCOUNT 1
SELECT connectionid
FROM outgoing_messages WITH (NOLOCK)
WHERE (campaignid_int = 3835)
我看到top(x)在某些情况下表现非常糟糕。我确定它正在进行全表扫描。也许您需要重建该特定列的索引?不过,上述情况值得一试。
答案 7 :(得分:0)
但是因为我指的是'top(1)' 意思是:给我任何一排。为什么会这样 首先爬过700k行 返回一个? - 30分钟前加速
很抱歉,还不能发表评论,但这里的答案是,当SQL服务器听到“Top 1”时,它不会理解人类相当于“把我找到的第一个”。而不是预期的“给我任何行”SQL Server去取所有找到的行中的第一个。 只有在知道这是在首先获取所有行之后,然后丢弃其余的时间。非常彻底,但在你的情况下不是很快。
正如其他所说的主要问题是您的索引的统计数据和选择性。如果表中有另一个唯一字段(如标识列),则首先尝试使用campaignid_int上的组合索引,然后尝试使用唯一列。由于您只对campaignid_int进行查询,因此它必须是密钥的第一部分。 听起来值得一试,因为这个索引应该具有更高的选择性,因此优化器可以比使用索引爬行更好地使用它。