SQL Server查询性能

3

我在一个繁忙的数据库中有一个存储过程,它经常成为昂贵查询列表中排名第一的项(远远超过其他查询)。这个查询非常简单,它只需要一个参数(@ID,整数),这个参数是表的主键,并选择与该ID匹配的记录。主键是具有聚集索引的标识字段,所以我不知道如何进一步优化它。

以下是查询语句:

CREATE PROCEDURE [dbo].[P_Call_Get]

    @ID int = null

AS

    select ID,
        AppID,
        AgentID,
        AgentLogin,
        Ext,
        VDN,
        VDNName,
        Skill,
        SkillName,
        CallFrom,
        TelNoFrom,
        ParentCallID,
        CallStart,
        ACWStart,
        CallEnd,
        Outcome,
        StageID,
        TxTo,
        TxSuccess,
        ServiceID,
        DiallerID,
        CRC,
        TSCallID,
        CallDirection,
        [Manual],
        CallBackAgent,
        CallBackDateTime,
        Notes
    from P_Call
    where (ID = @ID or @ID is null)

不确定发布执行计划的最佳方式 - 它只显示所有操作都由聚集索引扫描占用了 100%。


1
你可以贴出代码吗? - Marcelo Cantos
1
你能发布查询和执行计划吗? - Martin Smith
1
当你说它是最昂贵的时候,它有多少次读取?它被调用的频率是多少? - Mitch Wheat
它是否因使用频率高而显得最昂贵?如果它执行了10个逻辑I/O,但每天运行1000万次,那么它可能看起来很昂贵,但实际上它可能是可以接受的。 - ninesided
这被称为很多次!在一个有100个坐席,每个坐席每天接听3-400个电话的呼叫中心中,它将至少被调用一次。 - Macros
好的,那是一个很好的观点 - 有没有办法查看平均查询成本? - Macros
4个回答

8

我认为使用 where (ID = @ID or @ID is null) 会得到一个次优的计划。将其分成两个单独的查询,这样在 @Id 不为空的情况下,它将直接查找并在计划中出现搜索而不是扫描。您可以创建一个视图来避免重复(即没有任何 where 子句的查询)。

select ID,
    AppID,
    AgentID,
    AgentLogin,
    Ext,
    VDN,
    VDNName,
    Skill,
    SkillName,
    CallFrom,
    TelNoFrom,
    ParentCallID,
    CallStart,
    ACWStart,
    CallEnd,
    Outcome,
    StageID,
    TxTo,
    TxSuccess,
    ServiceID,
    DiallerID,
    CRC,
    TSCallID,
    CallDirection,
    [Manual],
    CallBackAgent,
    CallBackDateTime,
    Notes
from P_Call

将其拆分为两个查询确实做到了这一点 - 现在我的执行计划中出现了查找而不是扫描。这让我有点害怕,因为我已经在许多搜索多个可选条件的存储过程中使用了这种方法。本来想问一下是否有更好的方法,但我认为优化这些是一个单独的问题。 - Macros
我不确定是否有任何方法可以避免拆分为两个查询的方法。然而,如果您在查询中针对多个参数使用此方法,则保持复杂查询同步可能会有些麻烦。 - Martin Smith
@宏变量 无法避免拆分 - SQL服务器通常仅维护每个语句的单个执行计划。 - Justin

1
尝试清空过程缓存和内存缓冲区:
DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE

在测试过程性能之前这样做将防止使用缓存的执行计划和先前的结果缓存。

0

你可以使用表分区,这可能会解决问题。


0

这个表有多少行?你应该意识到,“聚集索引扫描”=全表扫描。


我之前没有这样做,但现在已经花了过去两天的时间根据此进行存储过程的优化。 - Macros
不错。你可能已经明白了为什么,但我应该解释一下优化器为什么选择了一个次优的计划。索引无法使用的原因是 WHERE 子句中的 (or @ID is null) 部分。NULL 值没有被索引。 - Mike Ritacco

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接