Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/85.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 如何优化INSERT语句_Sql Server_Tsql - Fatal编程技术网

Sql server 如何优化INSERT语句

Sql server 如何优化INSERT语句,sql-server,tsql,Sql Server,Tsql,我正在为数据仓库生成[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 A

我正在为数据仓库生成[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

查询速度很慢,因为您正在使用循环一次创建一个值

在处理值序列时,有一个“数字”表,表中的数字从1到您想要的项目数都很有用。通过选择或加入该表,您可以生成序列、确定差距等。Aaron Bertrand写了一篇关于如何创建数字表并使用它创建一组日期的文章

假设您已经有了这样一个数字n,创建日历表非常简单,如下所示:

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;
在您的情况下,选择的零件类似于:

;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
要生成数字表,可以使用以下语句:

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到您想要的项目数都很有用。通过选择或加入该表,您可以生成序列、确定差距等。Aaron Bertrand写了一篇关于如何创建数字表并使用它创建一组日期的文章

假设您已经有了这样一个数字n,创建日历表非常简单,如下所示:

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;
在您的情况下,选择的零件类似于:

;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
要生成数字表,可以使用以下语句:

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)

这也应该很快适用于您:

;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);

这也应该很快适用于您:

;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);

数据显示,这比小数字的数字表慢14倍,大数字的数字表慢35倍。您已经用递归替换了循环,但仍然一次生成一个值,而没有使用递归index@PanagiotisKanavosOP问了一个加快插入速度的方法,这可能不是最快的方法,但在我的开发盒上,它仍然只需要643毫秒就可以完成,这比他的29秒要快得多。根据我的研究,这比数字表中的小数字慢14倍,大数字慢35倍。您已经用递归替换了循环,但仍然一次生成一个值,而没有使用递归index@PanagiotisKanavosOP问了一个加快插入速度的方法,这可能不是最快的方法,但在我的开发盒上,它仍然只花了643毫秒就完成了,这比他的29秒要快得多。这个答案为什么以及如何帮助OP实现目标?请解释你的答案,不仅是为了OP,也是为了进一步阅读。谢谢有关更多信息,请阅读我们的最终目标是删除while循环。如果我们查看实际代码,@start值已经增加,即使这是代码中的关键部分。我们可以借助CTE而不是while循环来加速insert语句。这与Steve Ford发布的递归CTE相同。这个答案为什么以及如何帮助OP实现目标?请解释你的答案,不仅是为了OP,也是为了进一步阅读。谢谢有关更多信息,请阅读我们的最终目标是删除while循环。如果我们查看实际代码,@start值已经增加,即使这是代码中的关键部分。我们可以借助CTE而不是while循环来加速insert语句,这与Steve Ford发布的递归CTE相同。