【问题标题】:Importing Data Very Slow导入数据非常慢
【发布时间】:2015-06-16 21:40:13
【问题描述】:

每个月我需要导入 1-150 万行存档数据。我首先将其导入临时表(Tasks$),然后运行存储过程以根据需要插入到永久表中。导入临时表只需几秒钟。但是,存储过程需要 2-3 小时才能运行。有没有比我这样做更好的方法,或者这只是我正在尝试做的事情的本质,而且从长远来看没有办法?

如果我在不合并行的情况下运行它(没有 STUFF/SELECT 命令),它会运行得非常快,所以我知道这就是所有延迟的地方。

CREATE TABLE #Temp_DataArchive
(
    EmployeeID int,
    StartTime Time(0),
    Task nvarchar(25),
    Duration int,
    Details nvarchar(max),
    Weekdays nvarchar(max)
)

INSERT INTO #Temp_DataArchive
SELECT EmployeeID, StartTime, Task, Duration,
        STUFF((SELECT DISTINCT ', ' + A.Tasks FROM Tasks$ A
        WHERE (A.EmployeeID=B.EmployeeID) AND 
            (A.StartTime=B.StartTime) AND
            (A.Task=B.Task) AND
            (A.Duration=B.Duration)
        FOR XML PATH('')),1,1,'') As Details,
        STUFF((SELECT ', ' + A.Weekdays FROM Tasks$ A
        WHERE (A.EmployeeID=B.EmployeeID) AND 
            (A.StartTime=B.StartTime) AND
            (A.Task=B.Task) AND
            (A.Duration=B.Duration)
        FOR XML PATH('')),1,1,'') As Weekdays
FROM Tasks$ B
GROUP BY EmployeeID, StartTime, Task, Duration

为了完整起见,我应该补充一点,在完成之后,我还需要将 Weekdays 转换为单独的位类型列,我使用以下方法执行此操作,但这只需几秒钟即可运行。

INSERT INTO DataArchive
SELECT EmployeeID, StartTime, Task, Duration, Details,
    CASE WHEN Weekdays like '%Monday%' THEN 1 ELSE 0 END AS M,
    CASE WHEN Weekdays like '%Tuesday%' THEN 1 ELSE 0 END AS Tu,
    CASE WHEN Weekdays like '%Wednesday%' THEN 1 ELSE 0 END AS W,
    CASE WHEN Weekdays like '%Thursday%' THEN 1 ELSE 0 END AS Th,
    CASE WHEN Weekdays like '%Friday%' THEN 1 ELSE 0 END AS F,
    CASE WHEN Weekdays like '%Saturday%' THEN 1 ELSE 0 END AS Sa,
    CASE WHEN Weekdays like '%Sunday%' THEN 1 ELSE 0 END AS Su
FROM #Temp_DataArchive

drop table #Temp_DataArchive

编辑:解决方案 - 我的原始临时表 (Tasks$) 上缺少索引。添加这些索引后,插入到 #Temp_DataArchive 的时间从 2-3 小时缩短到 2-3 分钟。

【问题讨论】:

  • 很难说到底是什么问题,但是你看过执行计划了吗?只需检查以确保您排除了缺失或非最佳索引。
  • DataArchive 上有任何聚集索引吗?
  • Greg 也打败了我 - 但如果您决定需要索引,您可能会发现您需要在填充临时表之前删除它,然后在选择它之前重新添加它。
  • @Greg - 延迟发生在插入名为#Temp_DataArchive 的临时表中的第一个查询中。我实际上是在查询运行之前创建该表,我将修改我的原始帖子以显示它。
  • 不,没必要展示create table,我的意思是,继续隔离问题陈述。删除 INSERT 部分,并仅运行 SELECT。还是慢吗?如果是这样,请查看执行计划。

标签: sql-server sql-server-2008 import


【解决方案1】:

处理大量数据的 XML 处理速度让您放慢了速度。

我不明白您为什么要将已经很好地解析成行的数据放入逗号分隔的列表中。您不会获得任何好处,并使将来更难查询。只需按原样导入行。如果您需要将它们组合为界面中的视图,只需让客户端为他们正在查询的特定项目构建逗号列表。如果您想节省空间,您可以为每个(EmployeeID、StartTime、Task、Duration)创建一个身份 ID 字段,然后为您的任务(ID、Task)创建一个关系表。

【讨论】:

  • 我实际上对合并数据有非常特殊的需求。它不仅仅是一个传统的数据存档,而是从多个部门汇编的数据并根据特定标准完成报告。如果我没有按照需要的方式导入它,那么当有人出于这些目的提取报告时,他们首先需要这样做,然后在提取报告时每天进行几次计算。在这种情况下,像我这样做比将其保留为单独的行更具成本效益,因为单独的数据从未像这样在此服务器上使用。
【解决方案2】:

直到我发布结果,我才意识到您已经找到了解决方案(doi!)。我不会像我打算的那样对索引进行喋喋不休,但也会试一试这种格式。它通常对我来说更快,而且它是我的首选列表组合样式。

还请阅读有关使用 STUFF/FOR XML 的评论。

SELECT EmployeeID, Task, xtask.*, xdetail.*
FROM dbo.Task b
CROSS APPLY (
  SELECT [TaskList] = STUFF((
    SELECT DISTINCT
      N', ' + a.Task
    FROM dbo.Task a
    WHERE a.EmployeeID = b.EmployeeID
    FOR XML PATH(N''), TYPE
    -- Pull out the value from the xml or xml-escaped chars will stay escaped (ie. <>&)
    -- If you don't need to worry about that, you can remove this part to save a little time
  ).value(N'.', N'nvarchar(max)'), 1, 2, N'')
) xtask
CROSS APPLY (
  SELECT [DetailList] = STUFF((
    SELECT DISTINCT
      N', ' + a.Details
    FROM dbo.Task a
    WHERE a.EmployeeID = b.EmployeeID
    FOR XML PATH(N''), TYPE
  ).value(N'.', N'nvarchar(max)'), 1, 2, N'')
) xdetail
GROUP BY EmployeeID, Task

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-04
    • 2019-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-25
    • 2012-09-04
    相关资源
    最近更新 更多