Mad*_*dan 3 performance sql-server query-performance
我有一个查询如下:
SELECT @tenor_from =CONVERT(DATETIME,MIN(spc.maturity_date),103)
FROM source_price_curve spc
INNER JOIN #source_price_curve_list spcl
ON spc.source_curve_def_id = spcl.price_curve_id
WHERE spc.as_of_date >= @as_of_date_from
Run Code Online (Sandbox Code Playgroud)
运行需要将近 12 秒。从连接中删除临时表 #source_price_curve_list 会在不到 1 秒的时间内给出结果。
该source_price_curve表有 1.3 亿条记录。临时表#source_price_curve_list在输出中有一条记录(如下所示)。将来可能会包含更多数据
select * from #source_price_curve_list
rowID price_curve_id
1 1
Run Code Online (Sandbox Code Playgroud)
为什么与单记录临时表的内部连接会使查询花费更长的时间?我需要将查询运行时间减少到 1 秒以内。
以下链接提供了带有连接的查询的执行计划:
https://www.brentozar.com/pastetheplan/?id=BksaaWjSb
没有join to temp table的查询运行不到1秒,执行计划链接如下:
https://www.brentozar.com/pastetheplan/?id=BJ2_3boSZ
表 source_price_curve 创建如下:
CREATE TABLE [dbo].[source_price_curve](
[source_curve_def_id] [int] NOT NULL,
[as_of_date] [datetime] NOT NULL,
[Assessment_curve_type_value_id] [int] NOT NULL,
[curve_source_value_id] [int] NOT NULL,
[maturity_date] [datetime] NOT NULL,
[curve_value] [float] NOT NULL,
[create_user] [varchar](50) NULL,
[create_ts] [datetime] NULL,
[update_user] [varchar](50) NULL,
[update_ts] [datetime] NULL,
[bid_value] [float] NULL,
[ask_value] [float] NULL,
[is_dst] [int] NOT NULL,
CONSTRAINT [IX_unique_source_curve_def_id_index] UNIQUE NONCLUSTERED
(
[as_of_date] ASC,
[source_curve_def_id] ASC,
[maturity_date] ASC,
[is_dst] ASC,
[curve_source_value_id] ASC,
[Assessment_curve_type_value_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]
GO
ALTER TABLE [dbo].[source_price_curve] WITH NOCHECK ADD CONSTRAINT [FK_source_curve_def_id] FOREIGN KEY([source_curve_def_id])
REFERENCES [dbo].[source_price_curve_def] ([source_curve_def_id])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[source_price_curve] CHECK CONSTRAINT [FK_source_curve_def_id]
GO
Run Code Online (Sandbox Code Playgroud)
表中可用的以下索引source_price_curve(许多是很久以前创建的,可能未使用)
CREATE CLUSTERED INDEX [source_curve_def_id_index] ON [dbo].[source_price_curve]
(
[as_of_date] ASC,
[source_curve_def_id] ASC,
[maturity_date] ASC,
[is_dst] ASC,
[curve_source_value_id] ASC
)
CREATE NONCLUSTERED INDEX [source_price_curve_123] ON [dbo].[source_price_curve]
(
[source_curve_def_id] ASC,
[as_of_date] ASC
)
INCLUDE ( [maturity_date])
CREATE NONCLUSTERED INDEX [IX_PT_source_price_curve_as_of_date_curve_source_value_id]
ON [dbo].[source_price_curve]
(
[as_of_date] ASC,
[curve_source_value_id] ASC
)
INCLUDE ( [curve_value],
[maturity_date],
[source_curve_def_id])
CREATE NONCLUSTERED INDEX [IX_PT_source_price_curve_as_of_date_curve_source_value_id_Assessment_curve_type_value_id]
ON [dbo].[source_price_curve]
(
[as_of_date] ASC,
[curve_source_value_id] ASC,
[Assessment_curve_type_value_id] ASC
)
INCLUDE ( [curve_value],
[maturity_date],
[source_curve_def_id])
CREATE NONCLUSTERED INDEX [IX_PT_source_price_curve_maturity_date] ON [dbo].[source_price_curve]
(
[maturity_date] ASC
)
CREATE NONCLUSTERED INDEX [IX_PT_source_price_curve_source_curve_def_id_curve_source_value_id]
ON [dbo].[source_price_curve]
(
[source_curve_def_id] ASC,
[curve_source_value_id] ASC
)
INCLUDE ( [as_of_date],
[Assessment_curve_type_value_id],
[curve_value],
[is_dst],
[maturity_date])
CREATE NONCLUSTERED INDEX [IX_PT_source_price_curve_source_curve_def_id111]
ON [dbo].[source_price_curve]
(
[source_curve_def_id] ASC,
[Assessment_curve_type_value_id] ASC,
[curve_source_value_id] ASC,
[maturity_date] ASC,
[as_of_date] ASC
)
Run Code Online (Sandbox Code Playgroud)
我希望所有这些解释都有助于分析!提前致谢。
为什么与单记录临时表的内部连接会使查询花费更长的时间?
如果没有连接,优化器就足够聪明,可以通过从索引末尾读取一行来找到最小值。
不幸的是,当查询更复杂(例如,使用连接或分组子句)时,它目前无法应用相同类型的逻辑。要解决此限制,您可以重写查询以计算临时表中每行的局部最小值,然后找到全局最小值。
也许在 T-SQL 中表达这一点的最简单方法是使用APPLY运算符:
SELECT
-- Global minimum
@tenor_from = MIN(MinMaturityPerCurveID.maturity_date)
FROM #source_price_curve_list AS SPCL
CROSS APPLY
(
-- Minimum maturity_date per price_curve_id
SELECT TOP (1)
SPC.maturity_date
FROM dbo.source_price_curve AS SPC
WHERE
SPC.source_curve_def_id = SPCL.price_curve_id
and as_of_date >= @as_of_date_from
ORDER BY
SPC.maturity_date ASC
) AS MinMaturityPerCurveID;
Run Code Online (Sandbox Code Playgroud)
良好的性能依赖于每个price_curve_id. 您可能需要以下形式的索引:
CREATE NONCLUSTERED INDEX
[IX dbo.source_price_curve source_curve_def_id, maturity_date, as_of_date]
ON dbo.source_price_curve
(
source_curve_def_id,
maturity_date,
as_of_date
);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
13346 次 |
| 最近记录: |