我正在为数据仓库生成[Dim_Calendar]表。我在下面开发了一个查询,需要29秒才能执行&插入27k行。如果可能的话我想优化它。我确实理解虽然循环没有帮助性能,我不知道如何替换它以实现相同的结果。
我正在使用SQL Server 2012 BI版。
IF EXISTS(SELECT * FROM sys.indexes WHERE name='PK_Dim_Calendar_1' AND object_id = OBJECT_ID('Dim_Calendar'))
BEGIN
ALTER TABLE [dbo].[Dim_Calendar] DROP CONSTRAINT [PK_Dim_Calendar_1]
END
SET DATEFIRST 1--Sets Monday as 1st day of the week.
DECLARE @today DATETIME = ( SELECT GETDATE())
DECLARE @start DATETIME = DATEADD(dd, 1, (SELECT Max(date) FROM Dim_Calendar))
IF @start IS NULL
BEGIN
INSERT INTO [dbo].[Dim_Calendar]
VALUES (19000101, '1900-01-01', 'Monday', 1 ,'Unknown', 1, 'January', 1900, 1)
SET @start = '1940-01-01'
END
DECLARE @end DATETIME = (SELECT DATEFROMPARTS(YEAR(@today), 12, 31))
WHILE @start <= @end
BEGIN
INSERT INTO [dbo].[Dim_Calendar]
SELECT
YEAR(@start) * 10000 + MONTH(@start) * 100 + DAY(@start)
,@start
,DATENAME(dw, @start)
,DATEPART(wk, @start)
,'w/c ' + CONVERT(char(8), DATEADD(dd, 1 - DATEPART(dw, @start), @start), 3)
,DATEPART(mm, @start)
,DATENAME(MONTH, @start)
,YEAR(@start)
,DATEPART(QQ, @start)
SET @start = DATEADD(dd, 1, @start)
END
ALTER TABLE [dbo].[Dim_Calendar] ADD CONSTRAINT [PK_Dim_Calendar_1] PRIMARY KEY CLUSTERED
(
[FullDateID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
答案 0 :(得分:2)
查询很慢,因为您使用循环一次创建一个值。
在处理价值序列时,有一个数字&#39;表格,数字从1到您想要的多少项目。通过选择或连接该表,您可以生成序列,识别间隙等.Aaron Bertrand写了series of articles关于如何创建Numbers
表并使用它来创建一组日期。
假设您已经有这样的Numbers(n)
,创建一个Calendar表就像这样简单:
DECLARE @start DATE = '2005-07-01';
DECLARE @end DATE = DATEADD(DAY, -1, DATEADD(YEAR, 30, @start));
DECLARE @days int = DATEDIFF(DAY, @start, @end) + 1
SELECT TOP (@days)
d = CONVERT(DATE, DATEADD(DAY, n-1, @start))
INTO dbo.Calendar
FROM dbo.Numbers ORDER BY n;
在您的情况下,SELECT
部分将类似于:
;WITH Dates (d)
AS (
SELECT TOP (@days)
d = CONVERT(DATE, DATEADD(DAY, n-1, @start))
FROM dbo.Numbers
ORDER BY d)
SELECT
YEAR(d) * 10000 + MONTH(d) * 100 + DAY(d)
,d
,DATENAME(dw, d) ,DATEPART(wk, d)
,'w/c ' + CONVERT(char(8), DATEADD(dd, 1 - DATEPART(dw, d), d), 3)
,DATEPART(mm, d)
,DATENAME(MONTH, d)
,YEAR(d)
,DATEPART(QQ, d)
from Dates
要生成Numbers表,您可以使用以下语句:
SELECT TOP (1000000) n = CONVERT(INT, ROW_NUMBER() OVER (ORDER BY s1.[object_id]))
INTO dbo.Numbers
FROM sys.all_objects AS s1 CROSS JOIN sys.all_objects AS s2
OPTION (MAXDOP 1);
CREATE UNIQUE CLUSTERED INDEX n ON dbo.Numbers(n)
答案 1 :(得分:2)
这应该适合你(快速):
;WITH [dates]
AS
(SELECT @start AS [date]
UNION ALL
SELECT DATEADD(d, 1, [date]) AS [date]
FROM [dates]
WHERE [date] < @end)
SELECT
YEAR([date]) * 10000 + MONTH([date]) * 100 + DAY([date])
,[date]
,DATENAME(dw, [date])
,DATEPART(wk, [date])
,'w/c ' + CONVERT(char(8), DATEADD(dd, 1 - DATEPART(dw, [date]), [date]), 3)
,DATEPART(mm, [date])
,DATENAME(MONTH, [date])
,YEAR([date])
,DATEPART(QQ, [date])
FROM [dates]
OPTION (MAXRECURSION 32747);
答案 2 :(得分:0)
Try this
IF EXISTS(SELECT *
FROM sys.indexes
WHERE name = 'PK_Dim_Calendar_1'
AND object_id = OBJECT_ID('Dim_Calendar'))
BEGIN
ALTER TABLE [dbo].[Dim_Calendar]
DROP CONSTRAINT [PK_Dim_Calendar_1]
END
SET DATEFIRST 1--Sets Monday as 1st day of the week.
DECLARE @today DATETIME = (SELECT GETDATE())
DECLARE @start DATETIME = DATEADD(dd, 1, (SELECT Max(date)
FROM Dim_Calendar))
IF @start IS NULL
BEGIN
INSERT INTO [dbo].[Dim_Calendar]
VALUES (19000101,
'1900-01-01',
'Monday',
1,
'Unknown',
1,
'January',
1900,
1)
SET @start = '1940-01-01'
END
DECLARE @end DATETIME = (SELECT DATEFROMPARTS(YEAR(@today), 12, 31));
WITH T(start)
AS (SELECT @start
UNION ALL
SELECT start + 1
FROM T
WHERE T.start < @end)
INSERT INTO [dbo].[Dim_Calendar]
SELECT YEAR(start) * 10000 + MONTH(start) * 100 + DAY(start),
start,
DATENAME(dw, start),
DATEPART(wk, start),
'w/c '
+ CONVERT(CHAR(8), DATEADD(dd, 1 - DATEPART(dw, start), start), 3),
DATEPART(mm, start),
DATENAME(MONTH, start),
YEAR(start),
DATEPART(QQ, start)
FROM T
OPTION (MAXRECURSION 0);
ALTER TABLE [dbo].[Dim_Calendar]
ADD CONSTRAINT [PK_Dim_Calendar_1] PRIMARY KEY CLUSTERED ( [FullDateID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO