代码之家  ›  专栏  ›  技术社区  ›  Andrew Theken Tan Li Hau

CTE与条款内履行

  •  1
  • Andrew Theken Tan Li Hau  · 技术社区  · 16 年前

    好的,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');
    

    或:

    ???
    
    2 回复  |  直到 16 年前
        1
  •  2
  •   gbn    16 年前

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

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

    现在,in-vs-join-vs-exists是一个常见的问题。除了可读性之外,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)
    

    然而,我考虑的一个构造是,这将强制“中间物化”在我的搜索标题列表中。这个 也适用于现有或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)
    
        2
  •  0
  •   Andrew    16 年前

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

    正常的临界点(我再次检查了冒险工程)是在第65个项目上,它将计划更改为从搜索开始的扫描。

    推荐文章