2

约束

我目前无法更改查询,因为它是由应用程序动态构建的,我们无法在今天、本周甚至本月通过修复将代码推送到 PROD。这必须在数据库中解决。这就是我评估索引的原因。

我们的数据库中有一个表CaseHistory,它有大约 10MM 行。不可怕,但这是一种成长的痛苦。读取时间开始受到来自如下搜索的查询的影响:

select CaseNumber
    ,isnull(
        (
            select convert(varchar,min(CreationTimeGMT),101)
            from CaseHistory
            where CaseNumber = c.CaseNumber
                and ActionTypeID = 1
        ), 'N/A'
    ) as CreationTimeGMT
    ...
from [Case] c
where CaseNumber in (
    select CaseNumber from CaseHistory
    where ActionTypeID <> 1 and
        CreationTimeGMT >= '10/25/2013'
    ) AND
    CaseNumber in (
        select CaseNumber from CaseHistory
        where ActionTypeID <> 1 and
            CreationTimeGMT <= '10/25/2013'
    )

现在,乍一看可能会认为抓取的子查询CreateionTimeGMT可能是一个问题,但我不这么认为,因为我已经分析了执行计划。这个查询的执行计划使用了 99% 的处理SEEKIX_CaseHistory_1在下面的Current Indexes中显示)。为了进一步具体化我不认为是子查询的原因,直接针对 搜索CaseNumber,如下所示:

select CaseNumber
    ,isnull(
        (
            select convert(varchar,min(CreationTimeGMT),101)
            from CaseHistory
            where CaseNumber = c.CaseNumber
                and ActionTypeID = 1
        ), 'N/A'
    ) as CreationTimeGMT
    ...
from [Case] c
where CaseNumber = '123456'

sub 1s而上述查询在13s和之间运行15s

当前索引

IX_CaseHistory (CaseNumber (ASC))
IX_CaseHistory_1 (ActionTypeID (ASC))
IX_CaseHistory_2 (CreationTimeGMT (ASC))

所以,我想做的是在CaseNumber, ActionTypeID, CreationTimeGMT. 目前聚集索引位于IDENTITY PK.

为什么要集群?

因为我也希望这个查询运行得更快(每天执行 1000 次):

select  CaseHistoryID
    ,CaseNumber
    ,ActionTypeID
    ,CreationTimeGMT
    ,UserID
    ,Notes
from    CaseHistory
where   CaseNumber = @CaseNumber
order by CreationTimeGMT

但是,我有一个基本问题,我如何预测这会对写入时间产生什么样的影响?

4

2 回答 2

1

我如何预测这会对写入时间产生什么样的影响?

对于插入(我假设这就是您所说的“写入”),使用聚集索引时的主要问题是新数据将被插入到哪里。如果您通常将值添加到聚集索引的末尾(例如 Auto-Increment 键),那么写入应该非常快 - 它只是将新记录添加到末尾。

在您的情况下,我假设插入不是连续的,而是随机放置在现有数据中。在这种情况下,您需要考虑填充因子,这将决定现有记录之间留出多少空间来接受插入。

低填充因子以允许多次插入的代价是非索引列的读取时间更长,因为结果数据可能分布在多个页面上,因此需要更多 I/O。还需要更多磁盘空间,因为表需要为新插入分配空白空间(而不是仅仅自动增长)

我会将您的填充因子降低到 80(意味着为新插入留出 20% 的空间)并定期重组您的表以在记录之间为新数据保留一些空间。

于 2013-10-28T15:06:21.603 回答
1

你最好从头开始修改你的sql,

SELECT
        c.[CaseNumber],
        isnull(convert(varchar, min(h.[CreationTimeGMT]), 101), 'N/A'),
        ...
FROM [Case] c
LEFT JOIN [CaseHistory] h ON h.[CaseNumber] = c.[CaseNumber]
GROUP BY
        c.[CaseNumber]
WHERE
        h.[ActionTypeID] = 1
    AND
        EXISTS(
            SELECT
                    h.[CaseNumber]
            FROM [CaseHistory] h
            WHERE
                    h.[CaseNumber] = c.[CaseNumber]
                AND
                    h.[ActionTypeID] <> 1
                AND
                    h.[CreationTimeGMT] BETWEEN '10/25/2013' AND '10/25/2013');

一旦你这样做了,你可以看到 where 子句中的子查询(ies/y)是一个更复杂的命题。

我怀疑CaseHistory你的聚集索引应该保持 on CaseHistoryID,因为它是独一无二的。我很想在

`CaseNumber`, `ActionType`, `CreationTimeGMT`

但是,由于<> 1子查询中的“”,我也会尝试翻转条件,例如

                    h.[CreationTimeGMT] BETWEEN '10/25/2013' AND '10/25/2013'
                AND
                    h.[ActionTypeID] <> 1);

并添加此覆盖索引

`CaseNumber`, `CreationTimeGMT`, `ActionType`

与以往一样,性能的关键是首先获得最具选择性的条件。

我无法预测您数据库的实际成本,因为我没有您的数据、统计数据、环境等...

于 2013-10-28T15:10:01.447 回答