【问题标题】:Why is this sql script so slow and how to make it lightning fast?为什么这个 sql 脚本这么慢,如何让它快如闪电?
【发布时间】:2014-04-15 15:13:10
【问题描述】:

这是我的 sql 脚本

CREATE TABLE dbo.calendario (
    datacal DATETIME NOT NULL PRIMARY KEY,
    horautil BIT NOT NULL DEFAULT 1
);

-- DELETE FROM dbo.calendario;

DECLARE @dtmin DATETIME, @dtmax DATETIME, @dtnext DATETIME;

SELECT
    @dtmin = '2014-03-11 00:00:00'
    , @dtmax = '2030-12-31 23:50:00'
    , @dtnext = @dtmin;

WHILE (@dtnext <= @dtmax) BEGIN
    INSERT INTO dbo.calendario(datacal) VALUES (@dtnext);
    SET @dtnext = DATEADD(MINUTE, 10, @dtnext);
END;

基本上,我想创建一个日期间隔为 10 分钟的表格。循环插入了很多记录,但我认为执行它会很快。需要几分钟...

我使用的是 sql server 2008 r2。

感谢任何帮助。

【问题讨论】:

  • 也许在循环中引入显式事务会有所帮助。
  • 您的示例是一种程序/迭代方法。 SQL Server 通常使用基于集合的方法更有效。
  • 我同意明确的交易可能会有所帮助。但是,这是一个需要几分钟的问题吗?这只是一个一次性的设置脚本,对吧?如果您在生产系统上定期运行此程序,您可能需要重新考虑您的方法。
  • 是的,这将是生产中的一次性设置,但我仍在开发中 :)
  • 啊,“几个”在 20 分钟内,而不是 2-3 分钟。是的,我知道这会变得多么烦人。 :-)

标签: sql sql-server optimization sql-server-2008-r2


【解决方案1】:

您应该避免循环等,并尝试使用基于集合的方法。 (谷歌搜索“RBAR SQL”)

无论如何,这在我的笔记本电脑上运行只需 1 秒:

DROP TABLE dbo.calendario 
GO

CREATE TABLE dbo.calendario (
    datacal DATETIME NOT NULL PRIMARY KEY,
    horautil BIT NOT NULL DEFAULT 1
);

-- DELETE FROM dbo.calendario;

DECLARE @dtmin DATETIME, @dtmax DATETIME, @intervals int

SELECT @dtmin = '2014-03-11 00:00:00'
     , @dtmax = '2030-12-31 23:50:00'


SELECT @intervals = DateDiff(minute, @dtmin, @dtmax) / 10

;WITH 
  L0   AS(SELECT 1 AS c UNION ALL SELECT 1),
  L1   AS(SELECT 1 AS c FROM L0 AS A, L0 AS B),
  L2   AS(SELECT 1 AS c FROM L1 AS A, L1 AS B),
  L3   AS(SELECT 1 AS c FROM L2 AS A, L2 AS B),
  L4   AS(SELECT 1 AS c FROM L3 AS A, L3 AS B),
  L5   AS(SELECT 1 AS c FROM L4 AS A, L4 AS B),
  L6   AS(SELECT 1 AS c FROM L5 AS A, L5 AS B),
  Nums AS(SELECT ROW_NUMBER() OVER(ORDER BY c) AS n FROM L6)

INSERT INTO dbo.calendario(datacal)
SELECT DateAdd(minute, 10 * (n - 1), @dtmin)
  FROM Nums
 WHERE n BETWEEN 1 AND @intervals + 1

-- SELECT * FROM dbo.calendario ORDER BY datacal

【讨论】:

  • 这就是我喜欢stackoverflow的原因。谢谢。
【解决方案2】:

这段代码在我的机器上需要 23 秒(大部分是在排序中)

DECLARE @DateMin AS datetime = '2014-03-11 00:00:00';
DECLARE @DateMax AS datetime = '2030-12-31 23:50:00';

DECLARE @Test AS Table (
   datacal DATETIME NOT NULL PRIMARY KEY
);

WITH Counter AS (
    SELECT ROW_NUMBER() OVER (ORDER BY a.object_id) -1 AS Count
    FROM sys.all_objects AS a
         CROSS JOIN sys.all_objects AS b
)
INSERT INTO @Test (datacal)
SELECT DATEADD(minute, 10 * Count, @DateMin)
FROM Counter
WHERE DATEADD(minute, 10 * Count, @DateMin) <= @DateMax

【讨论】:

    【解决方案3】:

    已经有了一些有趣的答案。这是另一个基于集合的选项,它也使用公用表表达式。

    DECLARE @StartDate DATETIME = '2014-03-11 00:00:00';
    DECLARE @EndDate DATETIME = '2030-12-31 00:00:00';
    
    --CTE of days in the Start/End date range.
    WITH DaysTable AS
    (
        SELECT @StartDate AS CalendarDate
        UNION ALL
        SELECT DATEADD(dd, 1, CalendarDate)
        FROM DaysTable
        WHERE CalendarDate < @EndDate
    ) 
    --CTE of 10 min intervals for one day.
    ,MinsTable AS
    (
        SELECT CAST(0 AS DATETIME) MinutesDate
        UNION ALL
        SELECT DATEADD(MINUTE, 10, mt.MinutesDate)
        FROM MinsTable mt
        WHERE MinutesDate < DATEADD(MINUTE, -10, CAST(0 AS DATETIME) + 1)
    ) 
    SELECT DATEADD(MINUTE, DATEDIFF(MINUTE, CAST(0 AS DATETIME), mt.MinutesDate), dt.CalendarDate) Every10Min
    INTO #TestTable
    FROM MinsTable mt
    --Cross join for all 10 min intervals of all days in date range.
    CROSS JOIN DaysTable dt
    ORDER BY DATEADD(MINUTE, DATEDIFF(MINUTE, CAST(0 AS DATETIME), mt.MinutesDate), dt.CalendarDate)
    OPTION (MAXRECURSION 32767)
    
    SELECT *
    FROM #TestTable
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-10-08
      • 1970-01-01
      • 2022-11-11
      • 2014-03-12
      • 1970-01-01
      • 1970-01-01
      • 2014-03-21
      相关资源
      最近更新 更多