【问题标题】:CTE vs. IN clause performanceCTE 与 IN 子句性能
【发布时间】:2010-12-01 19:55:59
【问题描述】:

好的 SQL Server 大师,启动你的分析器。

  • 我在应用程序内存中有一个标题列表(大约 250 个)。
  • 我有一个数据库表“books”,其中包含超过一百万条记录,表的一列是“title”并且类型为 nvarchar。
  • “books”表还有一个名为“ISBN”的列
  • books.title 不是主键,不是唯一的,但已编入索引。

所以我想知道哪个更有效:

WITH titles AS (select 'Catcher and the Rye' as Title
                union all 'Harry Potter ...'
                ...
                union all 'The World Is Flat')

select ISBN from books, titles where books.title = titles.title;

或者:

select ISBN from books where title in ('Catcher and the Rye','Harry Potter',...,'The World Is Flat');

或者:

???

【问题讨论】:

    标签: sql sql-server sql-server-2005 performance tsql


    【解决方案1】:

    我希望您在标题索引中包含 ISBN 以避免键查找

    CREATE INDEX IX_Titles ON dbo.Books (Title) INCLUDE (ISBN)
    

    现在,IN vs JOIN vs EXIST 是这里的一个常见问题。除了可读性之外,CTE 无关紧要。就个人而言,我会使用存在,因为您会使用 JOIN 获得具有相同标题的书籍的副本,而人们经常会忘记这一点。

    ;WITH titles AS (select 'Catcher and the Rye' as Title
                union all 'Harry Potter ...'
                ...
                union all 'The World Is Flat')
    SELECT
        ISBN 
    FROM
        books
    WHERE
        EXISTS (SELECT * --or null or = all the same
            FROM
                titles 
            WHERE
                titles .Title = books.Title)
    

    但是,我考虑的一个构造是在我的搜索标题列表中强制“中间物化”。 also 也适用于存在或 CTE 解决方案。这可能对优化器有很大帮助。

    编辑:临时表是一个更好的选择,真的,正如史蒂夫在他的评论中提到的那样

    SELECT
        ISBN 
    FROM
        (
        SELECT TOP 2000000000
            Title
        FROM
            (select 'Catcher and the Rye' as Title
                    union all 'Harry Potter ...'
                    ...
                    union all 'The World Is Flat'
            ) foo
        ORDER BY
           Title
        ) bar
        JOIN
        books On bar.Title = books.Title
    
    
    SELECT
        ISBN 
    FROM
        books
    WHERE
        EXISTS (SELECT * --or null or = all the same
            FROM
                (
                SELECT TOP 2000000000
                    Title
                FROM
                    (select 'Catcher and the Rye' as Title
                            union all 'Harry Potter ...'
                            ...
                            union all 'The World Is Flat'
                    ) foo
                ORDER BY
                   Title
                ) bar
            WHERE
                bar.Title = books.Title)
    

    【讨论】:

    • 相信优化器。只有当您从实际测试中发现这不是一个明智的选择时,您才应该开始考虑尝试诱使特定行为。在任何情况下,使用 TOP/ORDER BY 是一种糟糕的方式,可以通过将搜索的标题插入索引表变量或临时表并加入它来做更易读的事情。事实上,未来的优化器改进可能会忽略 TOP,因为当它应用的表表达式少于 2000... 行时,它没有语义意义。
    • @Steve:好点,我忘了临时表/表变量。我会使用临时表进行统计/基数/估计。行:不是表变量。 TOP/ORDER BY 是我不再使用的东西(并且不确定性能),但它确实允许发生单个 SQL 调用。我也希望它能针对其他方法进行测试。
    【解决方案2】:

    考虑到这两个选项的选择,请避免使用 IN 子句,因为列表中的项目数量增加,查询计划将改变并很快从潜在的 Seek 转换为 Scan。

    正常的转折点(我仔细检查了冒险作品)是在第 65 项,它将计划从搜索更改为扫描。

    【讨论】:

      猜你喜欢
      • 2013-02-26
      • 1970-01-01
      • 2014-09-01
      • 2014-01-12
      • 2015-04-20
      • 2017-06-29
      • 2012-04-13
      • 2019-01-15
      相关资源
      最近更新 更多