【问题标题】:CTE Table optimisationCTE 表优化
【发布时间】:2020-02-07 08:11:31
【问题描述】:

我有一个包含 150 万行的表。它有一个有效的起点和一个有效的终点,我正在创建一个时间序列。我计划将这些合并到我拥有的其他表(行为类型变量,如每月付款/账单等),但是在使用下面的代码创建表时,它需要很长时间。在前 1000 名上运行大约需要 3 秒。前 10000 名大约需要 50 秒,所以我认为运行时间是指数级的。

下面是代码

SELECT
*
FROM
(
SELECT
    a.[PROP_NUM]
    ,b.table_code
    ,a.[RATE_UNIT_from]
    ,a.[RATE_UNIT_to]
    ,EOMONTH( a.[RATE_UNIT_from]) AS [Valid From]
    ,EOMONTH(CASE WHEN a.[RATE_UNIT_to] >= CAST(GETDATE() AS DATE) THEN CAST(GETDATE() AS DATE) ELSE a.[RATE_UNIT_to] END) AS [Valid To]
    ,ROW_NUMBER() OVER(PARTITION BY a.[PROP_NUM], EOMONTH(a.[RATE_UNIT_from]) ORDER BY a.[RATE_UNIT_to] DESC) AS [Row Number]
    INTO [dbo].[Historical LUC]
FROM [Grange_Prod].[dbo].[PROP_RATING_UNIT] as a
LEFT JOIN CODE_TABLE  as b
on a.prop_pru_tcode = b.table_code
WHERE a.[RATE_UNIT_TYPE_TCODE] = 'LUC' and b.table_type_code = 'LUC' and EOMONTH(CASE WHEN a.[RATE_UNIT_to] >= CAST(GETDATE() AS DATE) THEN CAST(GETDATE() AS DATE) ELSE a.[RATE_UNIT_to] END) >= '20131231'
) as z1
WHERE [Row Number] = 1
;
CREATE INDEX LUC ON [dbo].[Historical LUC] ([PROP_NUM], [Valid From], [Valid To])
;
DROP TABLE IF EXISTS [LUC Time Series]
;
WITH CTE AS
(
SELECT
    z1.[PROP_NUM]
    ,z1.[table_code]
    ,z1.[RATE_UNIT_from]
    ,z1.[RATE_UNIT_to]
    ,CASE WHEN z1.[Valid From] <= '20140101' THEN '20140101' ELSE z1.[Valid From] END AS [Valid From]
    ,z1.[Valid To]
FROM [dbo].[Historical LUC] AS z1
UNION ALL
SELECT
    [PROP_NUM]
    ,[table_code]
    ,[RATE_UNIT_from]
    ,[RATE_UNIT_to]
    ,EOMONTH(DATEADD(MONTH, 1, [Valid From])) AS [EOM Date]
    ,[Valid To]
    FROM CTE
WHERE [Valid From] < [Valid To]
)
SELECT
    [PROP_NUM]
    ,[table_code]
    ,EOMONTH(DATEADD(MONTH, 1, [Valid From])) AS [EOM Date]
    INTO [LUC Time Series]
FROM CTE AS a
ORDER BY [PROP_NUM], [Valid From]
OPTION (MAXRECURSION 32767)

有没有办法可以进一步增强这个查询?我愿意接受任何建议。

【问题讨论】:

  • 输出应该是什么样子的。
  • 您能否将问题简化为包含您需要的列和预期输出的表格
  • 该表将有 3 列。从今天到今天开放的每个月的房产编号、类型和日期。抱歉,我的手机无法添加实体表

标签: sql sql-server tsql common-table-expression


【解决方案1】:

我很惊讶 SQL Sever 在处理这个查询时遇到了困难。毕竟,递归查询不包含连接,因此对于每一行,您总是只生成一个新行(下个月直到周期结束)。

另一种方法可能是创建一个自 2014 年以来的月份表。少于 100 行。然后你可以写这样的东西,应该不会花太多时间来处理:

select *
from [dbo].[Historical LUC] h
join months m on m.month between h.[Valid From] and h.[Valid To];

【讨论】:

  • 最终表包含 525m 行。我认为这就是它挣扎的地方。
  • 是的,好吧,递归过程当然不知道它会生成多少数据,因此内存访问可能不是很好。这与我的查询不同,DBMS 只需要处理至少可以猜测的连接。并且 DBMS 是为了快速连接而编写的,所以机会很好:-)
  • 我将如何去填充前一个非空行以填补缺失的行?
  • 我不明白这个问题。对我来说,您似乎在其范围内的每个现有行和月生成一个结果行。这也正是 join 所做的。
  • 哦,我明白你在说什么。不要合并日期键以及仅属性键,并且有一些基于日期等分配类型的逻辑。干杯伙伴。希望这不会像 CTE 表那样花费数小时。
猜你喜欢
  • 2023-03-20
  • 2023-03-08
  • 2021-12-12
  • 1970-01-01
  • 1970-01-01
  • 2023-02-26
  • 1970-01-01
  • 1970-01-01
  • 2013-09-01
相关资源
最近更新 更多