【发布时间】:2021-01-04 21:10:00
【问题描述】:
使用 SQL Server 2017。
SQL FIDDLE:LINK
CREATE TABLE [TABLE_1]
(
PLAN_NR decimal(28,6) NULL,
START_DATE datetime NULL,
);
CREATE TABLE [TABLE_2]
(
PLAN_NR decimal(28,6) NULL,
PERIOD_NR decimal(28,6) NULL,
);
INSERT INTO TABLE_1 (PLAN_NR, START_DATE)
VALUES (1, '2020-05-01'), (2, '2020-08-05');
INSERT INTO TABLE_2 (PLAN_NR, PERIOD_NR)
VALUES (1, 1), (1, 2), (1, 5), (1, 6), (1, 5), (1, 6), (1, 17),
(2, 2), (2, 3), (2, 5), (2, 2), (2, 17), (2, 28);
CREATE VIEW ALL_PERIODS
AS
WITH rec_cte AS
(
SELECT
PLAN_NR, START_DATE,
1 period_nr, DATEADD(day, 7, START_DATE) next_date
FROM
TABLE_1
UNION ALL
SELECT
PLAN_NR, next_date,
period_nr + 1, DATEADD(day, 7, next_date)
FROM
rec_cte
WHERE
period_nr < 100
),
cte1 AS
(
SELECT
PLAN_NR, period_nr, START_DATE
FROM
rec_cte
UNION ALL
SELECT
PLAN_NR, period_nr, DATEADD(DAY, 1, EOMONTH(next_date, -1))
FROM
rec_cte
WHERE
MONTH(START_DATE) <> MONTH(next_date)
),
cte2 AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY PLAN_NR ORDER BY START_DATE) rn
FROM cte1
)
SELECT PLAN_NR, rn PERIOD_NR, START_DATE
FROM cte2
WHERE rn <= 100
表_1 列出了计划 (PLAN_NR) 及其开始日期 (START_DATE)。 表 2 列出了计划编号 (PLAN_NR) 和期间 (1 - X)。每个计划编号期间可能会出现多次,但也可能会丢失。 一个时期持续 7 天,除非该时期包括月份的变化。然后将周期分为月末前和月末后。
视图 ALL_PERIODS 根据此系统列出每个计划的 100 个期间。
我的问题是我想在视图中使用的以下选择的性能:
SELECT
t2.PLAN_NR
, t2.PERIOD_NR
, a_p.START_DATE
from TABLE_2 as t2
left outer join ALL_PERIODS a_p on t2.PERIOD_NR = a_p.PERIOD_NR and t2.PLAN_NR = a_p.PLAN_NR
从 TABLE_2 中的大约 4000 个条目开始,选择变得异常缓慢。
连接本身还没有减慢查询速度。只有额外的选择 a_p.START_DATE 一切都会变得异常缓慢。
我将视图读入一个临时表并对其进行了联接,没有遇到性能问题。 (4000 个条目需要 2 秒)。
所以我假设视图中使用的 CTE 是性能缓慢的原因。 不幸的是,我不能在视图中使用临时表,而且我不想将数据写入普通表。
SQL Server 中有没有办法改善 CTE 延迟?
【问题讨论】:
-
您在表上定义了哪些索引?查询计划是什么样的?
-
只插入整数时为什么要使用
decimal(28,6)? -
decimal(28,6) 只是出于习惯使用。在表中定义了多个索引......但我想它们不适合 sql fiddle 中的最小示例。我是否有意义扩展 fiddel
-
用计数表替换 rCTE,例如 @ItzikBenGan 的 this one
标签: sql-server common-table-expression