为什么这会加快我的SQL查询?

时间:2009-08-06 21:53:24

标签: sql optimization query-optimization performance

我从DBA朋友那里学到了一段时间来加速某些SQL查询。我记得他提到它与SQL Server如何编译查询有关,并且查询路径被强制使用索引值。

这是我的原始查询(需要20秒):

select Part.Id as PartId, Location.Id as LocationId
 FROM Part, PartEvent PartEventOuter, District, Location 
WHERE 
    PartEventOuter.EventType = '600'   AND PartEventOuter.AddressId = Location.AddressId  
    AND Part.DistrictId = District.Id   AND Part.PartTypeId = 15   
    AND District.SubRegionId = 11   AND PartEventOuter.PartId = Part.Id  
    AND PartEventOuter.EventDateTime <= '4/28/2009 4:30pm'   
    AND NOT EXISTS (
            SELECT PartEventInner.EventDateTime  
            FROM PartEvent PartEventInner
            WHERE PartEventInner.PartId = PartEventOuter.PartId
                AND PartEventInner.EventDateTime > PartEventOuter.EventDateTime 
                AND PartEventInner.EventDateTime  <= '4/30/2009 4:00pm')

这是“优化”查询(不到1秒):

select Part.Id as PartId, Location.Id as LocationId
 FROM Part, PartEvent PartEventOuter, District, Location 
WHERE 
    PartEventOuter.EventType = '600'   AND PartEventOuter.AddressId = Location.AddressId  
    AND Part.DistrictId = District.Id   AND Part.PartTypeId = 15   
    AND District.SubRegionId = 11   AND PartEventOuter.PartId = Part.Id  
    AND PartEventOuter.EventDateTime <= '4/28/2009 4:30pm'   
    AND NOT EXISTS (
            SELECT PartEventInner.EventDateTime  
            FROM PartEvent PartEventInner
            WHERE PartEventInner.PartId = PartEventOuter.PartId
                **AND EventType = EventType**
                AND PartEventInner.EventDateTime > PartEventOuter.EventDateTime 
                AND PartEventInner.EventDateTime  <= '4/30/2009 4:00pm')

任何人都可以详细解释为什么这样运行得更快?我只是想更好地理解这一点。

6 个答案:

答案 0 :(得分:3)

可能是因为您在没有EventType = EventType

的情况下获得了笛卡尔积

来自WikiPedia:http://en.wikipedia.org/wiki/SQL

“[SQL]使得进行笛卡尔连接(加入所有可能的组合)变得太容易了,当WHERE子句输入错误时会导致”失控“结果集。笛卡尔连接在实践中很少用到需要可以保证显式的CARTESIAN关键字。(SQL 1992引入了CROSS JOIN关键字,允许用户明确表示笛卡尔连接是有意的,但是没有谓词的简写“逗号连接”仍然是可接受的语法,它仍然会引用它错误。)“

在第一次查询时,您实际上要经历的行数超过了必要的数量。

http://www.fluffycat.com/SQL/Cartesian-Joins/

答案 1 :(得分:1)

EventType = Null是否有大量记录? 在添加aditional限制之前,子查询将返回所有那些Null记录,然后必须由外部查询中的每一行的Not Exists谓词进行扫描...因此,您对限制子查询返回的内容越多,减少必须扫描的行以验证不存在...

如果这是问题,如果你在子查询中将记录限制为EventType ='600',它可能会更快......

Select Part.Id as PartId, Location.Id as LocationId 
FROM Part, PartEvent PartEventOuter, District, Location 
WHERE PartEventOuter.EventType = '600'   
    AND PartEventOuter.AddressId = Location.AddressId      
    AND Part.DistrictId = District.Id   
    AND Part.PartTypeId = 15       
    AND District.SubRegionId = 11   
    AND PartEventOuter.PartId = Part.Id      
    AND PartEventOuter.EventDateTime <= '4/28/2009 4:30pm'       
    AND NOT EXISTS (SELECT PartEventInner.EventDateTime                  
                    FROM PartEvent PartEventInner
                    WHERE PartEventInner.PartId =  PartEventOuter.PartId
                       AND EventType = '600'                        
                       AND PartEventInner.EventDateTime > PartEventOuter.EventDateTime
                       AND PartEventInner.EventDateTime  <= '4/30/2009 4:00pm')

答案 2 :(得分:0)

奇怪,你有一个同时定义了EventTypeEventDateTime的索引吗?

修改
等等,EventType是一个可以为空的列吗? 如果Column = Column的值为FALSENULL将评估为EventType IS NOT NULL *。至少使用默认的SQL Server设置。

更安全的等价物是TRUE。看到它可以快速提供相同的结果吗?


*:我的T-SQL参考说它应该评估为ANSI_NULLSOFF设置为TRUE,但我的查询窗口则另有说明。 *现在不知所措*
任何裁决? FALSENULLUNKNOWN或{{1}}? :)得到SQL中的'二进制'逻辑:(

答案 3 :(得分:0)

当且仅当此索引的所有列都在查询中时,SQL Server才使用索引。

答案 4 :(得分:0)

您添加的每个非索引列都会执行表扫描。如果先在WHERE子句中缩小查询范围,则后续扫描速度会更快。因此,通过添加索引扫描,您的表扫描将以较少的数据运行。

答案 5 :(得分:0)

这种事情过去比现在更常见。例如,Oracle 6过去对您在WHERE子句中放置限制的顺序很敏感。您之所以感到惊讶,实际上是因为无论您如何构建SQL,我们都非常期待数据库引擎始终能够找到最佳的访问路径。 Oracle 6&amp; 7(之后我切换到MSSQL)也有提示扩展,你可以用来告诉数据库如何构建查询计划。

在这个特定情况下,如果没有看到实际的查询计划,很难给出确定的答案,但我怀疑不同之处在于你有一个使用EventType的复合索引,该索引不用于第一个查询但是用于第二个查询。这是不寻常的,因为我希望您的第一个查询仍然使用它,所以我怀疑数据库统计信息可能已过时,所以

重新统计

然后再试一次并在此处发布结果。