AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 326661
Accepted
MichaelD
MichaelD
Asked: 2023-05-02 21:30:10 +0800 CST2023-05-02 21:30:10 +0800 CST 2023-05-02 21:30:10 +0800 CST

是否有选项或提示可以提高“in”子句中具有多个值的查询的性能

  • 772

我们有一张 CustomerNote 表,其中包含 4 列 ID、CustomerID、Note、Date

CustomerID asc 上有一个索引,Date desc

当执行以下查询时

select top 30 
    Date 
from CustomerNote
where CustomerID in (1,5)
order by Date desc

使用了索引,但它仍在为 customerID 的 1 和 5 获取所有 CustomerNotes,然后进行排序/置顶,导致大量 CPU 使用率。 在此处输入图像描述

这是由于“in”子句中的多个值。我知道“in”子句的值永远不会超过 10,因此如果 sql server 迭代 10,每个 customerID 至少获取 30 个,然后进行合并、排序和排序,这将是一个更好的方法。是否有查询提示或选项来实现此目的?

sql-server
  • 3 3 个回答
  • 1072 Views

3 个回答

  • Voted
  1. Paul White
    2023-05-02T23:50:00+08:002023-05-02T23:50:00+08:00

    你可能最好手动编写你想要的转换,但本着找到优化器可以为你做的事情的精神,只需最少的更改:

    SELECT TOP (30) 
        CN.[Date] 
    FROM dbo.CustomerNote AS CN
    WHERE 
        CN.CustomerID IN (SELECT 1 UNION SELECT 5)
    ORDER BY 
        CN.[Date] DESC;
    

    计划

    是的,如果优化器在不更改语法的情况下为您探索这种选项,那就太好了。

    示例表和数据

    CREATE TABLE dbo.CustomerNote
    (
        CustomerID integer NOT NULL,
        [Date] datetime NOT NULL
    );
    
    WITH 
        N (n) AS
        (
            SELECT 
                SV.number 
            FROM master.dbo.spt_values AS SV
            WHERE
                SV.[type] = N'P'
                AND SV.number >= 1
        )
    INSERT dbo.CustomerNote
        WITH (TABLOCKX)
    (
        CustomerID, 
        [Date]
    )
    SELECT 
        C.n, 
        DATEADD
        (
            MINUTE, 
            -D.n * RAND(CHECKSUM(NEWID())) * 1000,
            GETDATE()
        )
    FROM N AS C
    CROSS JOIN N AS D
    WHERE
        C.n BETWEEN 1 AND 9;
    
    CREATE NONCLUSTERED INDEX 
        [IX dbo.CustomerNote CustomerID, Date-] 
    ON dbo.CustomerNote
        (CustomerID, [Date] DESC);
    

    为 10 个不同的客户加载 2047 个随机日期值:

    SELECT CN.CustomerID, NumRows = COUNT_BIG(*) 
    FROM dbo.CustomerNote AS CN
    GROUP BY CN.CustomerID
    ORDER BY CN.CustomerID;
    
    客户ID 行数
    1个 2047
    2个 2047
    3个 2047
    4个 2047
    5个 2047
    6个 2047
    7 2047
    8个 2047
    9 2047

    运行解决方案代码会生成一个执行后计划,其中从针对客户 1 的有序索引查找中读取14 行,并从针对客户 5 的类似查找中读取17 行:

    实际计划

    数据库<>小提琴演示

    该计划不会读取每个客户的所有 2047 行。

    另请注意,此解决方案不需要排序运算符。


    该解决方案非常通用,尽管Merge Concatenation需要满足一些排序条件。

    如果要投影不同的列,该列需要成为索引键的一部分(而不是作为包含)以满足排序要求;或者您可以只获取表的一个键,并在找到所需的少量键后作为单独的步骤查找额外的列。

    带有额外列的其他演示:

    • https://dbfiddle.uk/nNKi4m0P(添加到索引键)
    • https://dbfiddle.uk/D4fNdMf2(键加查找)
    • 9
  2. Best Answer
    Charlieface
    2023-05-02T23:41:45+08:002023-05-02T23:41:45+08:00

    VALUES加入表值参数、临时表或子句似乎会更好。这意味着每个CustomerID将在关联中单独查询APPLY然后排序。

    select top (30) 
      cn.Date 
    from (values
        (1),
        (5)
    ) v(CustomerID)
    cross apply (
        select top (30) cn.*
        from CustomerNote cn
        where v.CustomerID = cn.CustomerID
        order by
          cn.Date desc
    ) cn
    order by
      cn.Date desc;
    
    • 7
  3. White Owl
    2023-05-02T22:08:58+08:002023-05-02T22:08:58+08:00

    和总是最后应用top。order by您不能期望优化器根据子句对行进行预过滤order by。

    但是您可以通过使用类似的方法来减少排序记录的数量

    select top 30 
        Date 
    from CustomerNote
    where CustomerID in (1,5) and Date>datadd(day, -60, getdate())
    order by Date desc
    

    因此,假设您在过去 60 天内有 30 多条记录,您将获取这些记录,对它们进行排序,并丢弃多余的。实际天数,您将不得不根据您的数据进行猜测。

    • -4

相关问题

  • SQL Server - 使用聚集索引时如何存储数据页

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve