【问题标题】:SQL WHERE Clause OptimizationSQL WHERE 子句优化
【发布时间】:2014-08-21 07:29:12
【问题描述】:

假设我有以下三种类型:

  • 类型1
  • 类型2
  • 类型3

从优化的角度来看(忽略可维护性;我知道如果添加新类型,第一个选项不太可能中断);像这样写我的where子句会更有效吗:

WHERE p.TypeId IN (Type1, Type2)

WHERE p.TypeId <> Type3

【问题讨论】:

  • p.typeid 可以为 NULL 吗?
  • 从理论上讲,这是一个有趣的问题,但我不禁想知道是否值得担心......
  • 它们之间的差异可能非常小,以至于您在现实世界的应用程序中永远不会注意到。不过请注意,您应该提及数据库并尝试在您的系统上使用您的数据运行变体。
  • 我认为答案是“视情况而定”。取决于表的大小、索引的存在、列基数和值分布、是否收集分布统计信息等。换句话说,直到你测试你才会知道。
  • @radarbob --“IN (..) 最终对括号中的每个值进行 ORing”——这纯粹是推测。

标签: sql optimization


【解决方案1】:

您的第二个选择:

WHERE p.TypeId <> Type3

写起来会更有效率,因为它使用的字符更少,除非你在 iPad 上,在这种情况下,获取 字符会很慢!

在执行方面,它的执行速度也会更快。显然,它要做的工作更少,因为只需要一次比较,所以无论你优化它的哪种方式 都将比具有两个元素的 IN 更快。

【讨论】:

    【解决方案2】:

    这可能取决于索引的配置方式和表中的数据,但对于一个简单的测试用例,可以证明它们可以在 SQL Server 2005 中创建相同的查询计划。

    以下代码在 SQL Server 2005 实例上运行,为查询的 OR、IN 和不等式版本生成了相同的查询计划。每个查询产生相同数量的记录。第一组查询使用 3 值均等分布。第二组查询使用 10 值均等分布。

    CREATE TABLE #Test (TestID int, TestTypeID int);
    
    WITH TallyTable AS
    (
        SELECT
        TOP 10000
        ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS Tally
        FROM            sys.objects s1
        CROSS JOIN      sys.objects s2
    ), InsertList AS
    (
        SELECT
            Tally AS TestID,
            Tally % 3 AS TestTypeID
        FROM    TallyTable
    )
    INSERT INTO #Test
        (
            TestID,
            TestTypeID
        )
    SELECT
        TestID,
        TestTypeID
    FROM        InsertList;
    
    SELECT
        TestTypeID
    FROM        #Test
    WHERE       TestTypeID = 0
    OR          TestTypeID = 2;
    
    SELECT
        TestTypeID
    FROM        #Test
    WHERE       TestTypeID IN (0,2);
    
    SELECT
        TestTypeID
    FROM        #Test
    WHERE       TestTypeID <> 1;
    
    CREATE INDEX TestIndex ON #Test (TestTypeID);
    
    SELECT
        TestTypeID
    FROM        #Test
    WHERE       TestTypeID = 0
    OR          TestTypeID = 2;
    
    SELECT
        TestTypeID
    FROM        #Test
    WHERE       TestTypeID IN (0,2);
    
    SELECT
        TestTypeID
    FROM        #Test
    WHERE       TestTypeID <> 1;
    
    DROP INDEX TestIndex ON #Test;
    
    TRUNCATE TABLE #Test;
    
    WITH TallyTable AS
    (
        SELECT
        TOP 10000
        ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS Tally
        FROM            sys.objects s1
        CROSS JOIN      sys.objects s2
    ), InsertList AS
    (
        SELECT
            Tally AS TestID,
            Tally % 10 AS TestTypeID
        FROM    TallyTable
    )
    INSERT INTO #Test
        (
            TestID,
            TestTypeID
        )
    SELECT
        TestID,
        TestTypeID
    FROM        InsertList;
    
    SELECT
        TestTypeID
    FROM        #Test
    WHERE       TestTypeID = 0
    OR          TestTypeID = 2
    OR          TestTypeID = 3
    OR          TestTypeID = 4
    OR          TestTypeID = 5
    OR          TestTypeID = 6
    OR          TestTypeID = 7
    OR          TestTypeID = 8
    OR          TestTypeID = 9;
    
    SELECT
        TestTypeID
    FROM        #Test
    WHERE       TestTypeID IN (0,2,3,4,5,6,7,8,9);
    
    SELECT
        TestTypeID
    FROM        #Test
    WHERE       TestTypeID <> 1;
    
    CREATE INDEX TestIndex ON #Test (TestTypeID);
    
    SELECT
        TestTypeID
    FROM        #Test
    WHERE       TestTypeID = 0
    OR          TestTypeID = 2
    OR          TestTypeID = 3
    OR          TestTypeID = 4
    OR          TestTypeID = 5
    OR          TestTypeID = 6
    OR          TestTypeID = 7
    OR          TestTypeID = 8
    OR          TestTypeID = 9;
    
    SELECT
        TestTypeID
    FROM        #Test
    WHERE       TestTypeID IN (0,2,3,4,5,6,7,8,9);
    
    SELECT
        TestTypeID
    FROM        #Test
    WHERE       TestTypeID <> 1;
    
    DROP TABLE #Test;
    

    该集合使用 3 值不等分布,也产生相同的查询计划。

    CREATE TABLE #Test (TestID int, TestTypeID int);
    
    WITH TallyTable AS
    (
        SELECT
        TOP 10000
        ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS Tally
        FROM            sys.objects s1
        CROSS JOIN      sys.objects s2
    ), InsertList AS
    (
        SELECT
            Tally AS TestID,
            CASE
                WHEN Tally % 1000 = 0 THEN 2
                WHEN Tally % 100 = 1 THEN 1
                ELSE 0
            END AS TestTypeID
        FROM    TallyTable
    )
    INSERT INTO #Test
        (
            TestID,
            TestTypeID
        )
    SELECT
        TestID,
        TestTypeID
    FROM        InsertList;
    
    SELECT
        TestTypeID
    FROM        #Test
    WHERE       TestTypeID = 0
    OR          TestTypeID = 2;
    
    SELECT
        TestTypeID
    FROM        #Test
    WHERE       TestTypeID IN (0,2);
    
    SELECT
        TestTypeID
    FROM        #Test
    WHERE       TestTypeID <> 1;
    
    CREATE INDEX TestIndex ON #Test (TestTypeID);
    
    SELECT
        TestTypeID
    FROM        #Test
    WHERE       TestTypeID = 0
    OR          TestTypeID = 2;
    
    SELECT
        TestTypeID
    FROM        #Test
    WHERE       TestTypeID IN (0,2);
    
    SELECT
        TestTypeID
    FROM        #Test
    WHERE       TestTypeID <> 1;
    
    DROP TABLE #Test;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多