【发布时间】:2026-01-04 05:15:01
【问题描述】:
我在生产中有一个数据库表,用于存储给定项目的workflow;表中的每条记录基本上代表特定日期的项目状态。
过度简化的表结构是这样的:
工作流程表
|-------------|------------|---------|----------------|
| Category | ItemCode | Status | InsertDate |
|-------------|------------|---------|----------------|
| Cat1 | Foo1 | 01 | 2012-01-01 |
|-------------|------------|---------|----------------|
| Cat1 | Foo1 | 02 | 2012-03-02 |
|-------------|------------|---------|----------------|
| Cat1 | Foo1 | 03 | 2012-04-01 |
|-------------|------------|---------|----------------|
| Cat1 | Foo2 | 01 | 2012-04-06 |
|-------------|------------|---------|----------------|
| Cat1 | Foo2 | 02 | 2012-05-07 |
|-------------|------------|---------|----------------|
| Cat1 | Foo2 | 04 | 2012-05-09 |
|-------------|------------|---------|----------------|
| Cat2 | Foo3 | 01 | 2011-02-03 |
|-------------|------------|---------|----------------|
| ... | ... | .. |.... |
|-------------|------------|---------|----------------|
因此,在 2012-01-01,项目 Foo1 已达到状态 01;在 2012-04-01 已达到状态 03 等等。
StoredProcedure PR_GetCategoryItemsInformation 以给定的Category 作为输入,读取工作流表并给出如下结果:
@输入:Cat1
输出:
|------------------|---------------|------------------|---------------------|
| Category | ItemCode | DateOfFirstRecord| StatusOfLatestRecord|
|------------------|---------------|------------------|---------------------|
| Cat1 | Foo1 | 2012-01-01 | 03 |
| Cat1 | Foo2 | 2012-04-06 | 04 |
SP,给定一个Category,对于每个ItemCode需要获取工作流的第一行以读取InsertDate,并获取工作流的最后一行以获取当前的Status。
它归结为如下所示的 SP 实现:
CREATE PROCEDURE dbo.PR_GetFooItemInformation
@Category CHAR(3)
AS
BEGIN
CREATE TABLE #TabTemp (
Category CHAR(3),
ItemCode CHAR(3),
Status CHAR(2),
InsertDate DATETIME
)
CREATE CLUSTERED INDEX XIE1TabTemp
ON #TabTemp (...)
CREATE NONCLUSTERED INDEX XIE2TabTemp
ON #TabTemp (...)
INSERT INTO #TabTemp
SELECT
Category,
ItemCode,
Status,
InsertDate
FROM Workflow
WHERE (Some rules to cut down the number of rows)
SELECT
T1.Category,
Item.ItemCode,
T1.InsertDate,
T2.Status
FROM
Item
INNER JOIN
#TabTemp as T1 ON Item.ItemCode = Workflow.ItemCode
INNER JOIN
#TabTemp as T2 ON Item.ItemCode = Workflow.ItemCode
WHERE
...
AND
T1.InsertDate= SELECT
MIN(InsertDate)
FROM
#TabTemp as T3
WHERE ..
AND
T2.InsertDate = SELECT
MAX(InsertDate)
FROM
#TabTemp as T4
WHERE ..
SP 多年来一直按预期工作(2005 年),但几个月前它开始出现随机超时;由于workflow 表的记录数在增长(250 万并且还在增加),它的性能肯定会越来越差*。
这些表已正确编入索引,而且就其价值而言,sql 管理工作室不建议在 SP 上建立任何进一步的索引。
不使用临时表的同一个 SP 速度要慢 4 倍。
此时的临时表在每次调用时平均填充了 150 万行。
据我有限的 dba 知识,这个问题与 MIN 和 MAX 函数有关,需要计算这些函数才能到达给定类别的每个项目的第一行和最后一行。
我省略了有关工作流表和 SP 实现的一些细节,但我希望我所描述的内容足以了解问题。
最后一个问题:
你知道处理这种情况的任何 sql 策略甚至 sql-server 专有解决方案吗?
我有什么样的限制?
好吧,SP 用于 BackOffice 函数,应该返回所有实时记录,而不是预处理的子集。
* 我不是 dba;其中一位 dba 目前正在他黑暗的实验室里研究这个小怪物。
【问题讨论】:
-
表是否有id字段,PRIMARY KEY?
-
您知道减速是由于工作流表中的行数增加,还是由于插入临时表的行数?了解表上的索引以及它们是否已被维护/重建以减少碎片也很有帮助。您是否查看过此过程的(估计和/或实际)执行计划?
标签: sql sql-server sql-server-2008 stored-procedures timeout