我编写了一个相当简单的存储过程,它接受一些数据,选择一个值,插入几条记录,然后返回该值。但是在我们的生产环境中执行时间过长,我最终可能希望它一天运行几十万次,即使我们只运行它说 30000 次,它也会对其他进程产生不利影响。
我首先查看查询并在 where 子句中使用的日期字段上添加索引。然后我运行 SQL Server Profiler——将结果输入 Tuning Advisor 并实施它提出的索引建议。过去,我看到该工具需要非常丑陋的索引,但这次它只需要一个有意义的添加,所以我添加了它。这些步骤中的每一个都有帮助。但是还是太慢了。
很容易发现第一个查询是阻塞,而不是几乎瞬时的两个插入。所以这就是我当时所拥有的,包括子查询运行时:
--all combined, this typically takes in the range of 1200-1500 ms but occasionally spikes up to ~2200 ms
select coalesce(
(
--when the following is run, this takes ~690 ms
select MIN(maxes.imbsn)
from (
--when the following is run without the higher limiting scopes, this takes ~3600 ms
select imbsn, MAX(assignmentDate) maxAD
from imbsnAssignments
group by imbsn
) maxes
where datediff(d, maxes.maxAD, GETDATE()) > 90
)
,
(
--this is rarely executed but takes ~0 ms when it is
select max(imbsn)+1 from imbsnAssignments
)
)
基于那些时间,似乎合并正在搞砸事情(我想如果我曾经弄清楚如何阅读它,我可以用执行计划来验证它,但我没有 - 计划在很大程度上仍然存在对我可怜的大脑来说是不透明的)。为了摆脱合并,我将查询更改为:
--this runs ~480-700 ms
select MIN(maxes.imbsn)
from (
select imbsn, MAX(assignmentDate) maxAD
from imbsnAssignments
group by imbsn
union
select max(imbsn)+1, getDate()
from imbsnAssignments
) maxes
where datediff(d, maxes.maxAD, GETDATE()) > 90
这是一个很大的改进。但它仍然很慢。
我确认 Profiler-Tuning Advisor 仍然不希望我在来这里询问您之前进行任何更改。我认为这让我有两种方法:1)保持基本算法,但从中挤出更高的效率,或者 2)通过我不知道但一种显而易见的方法切换到一些更聪明的方法来获得相同的基本效果致那些嗅出我在这里从事某种反模式的大脑袋。
提前感谢您的时间和关注!
我不确定这些附加信息的预期格式是什么,但我会试一试。表格是:
CREATE TABLE [dbo].[imbsnAssignments](
[id] [int] IDENTITY(1,1) NOT NULL,
[imbsn] [int] NOT NULL,
[assignmentDate] [date] NOT NULL,
[jobCode] [varchar](10) NOT NULL,
[name] [varchar](45) NOT NULL,
[a1] [varchar](45) NOT NULL,
[a2] [varchar](45) NOT NULL,
[a3] [varchar](45) NOT NULL,
[a4] [varchar](45) NOT NULL,
[city] [varchar](40) NOT NULL,
[state] [char](10) NOT NULL,
[zip] [varchar](10) NOT NULL,
[batchIdent] [varchar](256) NOT NULL,
CONSTRAINT [PK_imbsnAssignments] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
我怀疑这不是显示索引的“正确”方式,但是:
TableName IndexName IndexType
imbsnAssignments PK_imbsnAssignments CLUSTERED
imbsnAssignments IX_imbsnAssignments_assignmentDate NONCLUSTERED
imbsnAssignments _dta_index_imbsnAssignments_36_149575571__K2_3 NONCLUSTERED
执行计划:
|--Stream Aggregate(DEFINE:([Expr1013]=MIN([partialagg1018])))
|--Concatenation
|--Stream Aggregate(DEFINE:([partialagg1018]=MIN([IMB].[dbo].[imbsnAssignments].[imbsn])))
| |--Filter(WHERE:([Expr1003]<dateadd(day,(-90),getdate())))
| |--Stream Aggregate(GROUP BY:([IMB].[dbo].[imbsnAssignments].[imbsn]) DEFINE:([Expr1003]=MAX([IMB].[dbo].[imbsnAssignments].[assignmentDate])))
| |--Index Scan(OBJECT:([IMB].[dbo].[imbsnAssignments].[_dta_index_imbsnAssignments_36_149575571__K2_3]), ORDERED FORWARD)
|--Stream Aggregate(DEFINE:([partialagg1018]=MIN([Expr1009])))
|--Compute Scalar(DEFINE:([Expr1009]=[Expr1008]+(1)))
|--Stream Aggregate(DEFINE:([Expr1008]=MAX([IMB].[dbo].[imbsnAssignments].[imbsn])))
|--Top(TOP EXPRESSION:((1)))
|--Index Scan(OBJECT:([IMB].[dbo].[imbsnAssignments].[_dta_index_imbsnAssignments_36_149575571__K2_3]), ORDERED BACKWARD)