【问题标题】:SQL Server TSQL Stored Procedure / Queries SlowSQL Server TSQL 存储过程/查询慢
【发布时间】:2015-03-20 00:46:50
【问题描述】:

我有一个 SQL Server TSQL 问题。我的存储过程正在运行 非常缓慢地。关于使用集合操作改进这些查询的任何建议 将不胜感激。

请记住,我无法控制数据的存储方式。

我有两个表格,格式如下:

  1. 人员 ID、姓名、DeletedFlag、SchedTotal、WorkedTotal、DeptNum、DeptName、 [和这个问题的其他 20 个不相关的列] 这是一个临时表 预填充用户选择的人员和用户 可以访问。

  2. 人员 ID、记录类型、年份、HexMap

对于每个人,一个特定的记录将有两条或零条记录 年。一份用于计划时间的记录,一份用于工作时间的记录。十六进制图 是一个字符串(每两个字符代表总计划或工作 时间)。我最多可以有 732 个字符(每天一对),总是 从 1 月 1 日开始。我写了一个函数来拆分字符串,所以我不是 担心这个。

想要的结果

第一个表 SchedTotal 和 WorkedTotal 字段更新为总计 根据用户选择的日期从第二个表中获取。日期 范围可以在一个日历年内或跨多个日历年。

我可以做到,但我认为我采取的步骤太多了。下面是什么 我目前正在做。建议赞赏:

A. TEMP 结果表 1:对于用户的每个日历年 选择的日期范围(While 循环):将 上表 1 所列人员的 personid、recordtype 和 hexmap。

  WHILE (@YearCount <= @YearEnd)
   ....
  INSERT INTO #Tmp_HexMap (personid, hexMap, recordtype) 
  SELECT T1.personid, H.HexMap, H.recordtype 
  FROM [MyDatabase_' + CONVERT(Varchar(5),@DatabaseNum) + '].[dbo].[hextable] H 
  INNER JOIN #Tmp_Persons T1 ON T1.Personid = H.PersonID 
  WHERE Year = ' + CONVERT(Varchar(5),@YearCount)

B.临时结果表 2:仍处于每年的 While 循环中。一世 为每个人逐行计数(内部 While 循环) 并将我的十进制结果插入另一个临时表 十六进制拆分器函数——它返回一个带小数的表变量 结果。我添加了 personid 、预定或工作日期和预定 和工作时间。

  WHILE (@PersonID IS NOT NULL)
   ....
  INSERT INTO #Tmp_scheduledtime (personid, scheddate, scheduledworkedtime) 
  SELECT @personid as personid, 
  DATEADD(dd,(Row_Number() OVER(Order by (Select NULL))+(@CurrentStartInt-1)-1),@YearStartDate) AS SchedDate, 
  workedtime FROM Report_Maint.dbo.workedtimesplit(@HexMap,@CurrentStartInt,@WorkedTimeDateINT) 

C.临时结果表 3 和 4:在 while 循环之外,我将总计插入临时表:

 INSERT INTO #Tmp_Grouped1 (personid, ScheduledTotal, WorkedTotal)
 SELECT personid, ISNULL(SUM(scheduledworkedtime),-1.00) From #Tmp_scheduledtime
 GROUP BY personid

D.最后,我更新了原表:

    'UPDATE #Tmp_Persons ' +
    'SET HoursSched = ScheduledWorkedTotal ' +
    'From #Tmp_Grouped1 TG ' +
    'WHERE TG.Personid = #Tmp_Persons.Personid ' +
  '  AND #Tmp_persons.PeriodBegin >= ' + '''' + CONVERT(nvarchar(24),@DateBegin,121) + '''' + ' ' +
    'AND #Tmp_persons.PeriodEnd <= ' + '''' + CONVERT(nvarchar(24),@DateEnd,121) + ''''

关于将这些变成一两个查询而不是通过 while 循环的任何想法? 感谢您的帮助!

标记

【问题讨论】:

  • 能否提供一些示例数据和预期结果/
  • 是的,我需要您列出所有表格和使用的列以及示例数据和您想要的结果,以帮助您。
  • 为简单起见(和换行)假设每年只有 25 天(十六进制对)。用户查询 2013 年 1 月 16 日 - 2015 年 1 月 18 日的开始范围。这意味着我们从第 16 天(第 32 个字符)开始计算 2013 十六进制对,并在第 18 天(第 36 个字符)结束计算 2015 十六进制对.临时表 1:PersonID,Name,DeletedFlag,SchedTotal,WorkedTotal,DeptNum,DeptName 1,Joe,N,-1,-1,Dept1,AcctDept 2,Bill,Y,-1,-1,Dept2,Credit 3,Bob ,N,-1,-1,Dept4,HR 4,Jill,N,-1,-1,Dept1,AcctDept 5,Marcy,N,-1,-1,Dept2,Credit
  • 第2部分响应: - 临时表2:是PersonID,记录类型,年份,HexMap 1,0,2013,00006060606060000060606060600000606060606000006060 [672] 1,1,2013,00006F606060600000756060606000006F6060600000666060 [693] 1,0,2014 ,004A6060006060604A60000060604A60000000606060606000 [1566] 1,1,2014,00575B000049645D5A625C00605A572D5347005F585B7F5E00 [1691] 1,0,2015,60606000006060606060000060606060600000606060606054 [1248] 1,1,2015,00000000005F60606060000060606060000000600060606000 [863] 2,0,2015,70606C73006A79606E000000749578687100006F6B9471676F [1466] 跨度>
  • 2,1,2015,006D776F717179006F6E006A6C7B006B72696D6971007B7569 [1570] 3,0,2014,00006040005F6060606000006060 [831] 3,1,2014,0060606400606060606000006060 [964] 4,0,2014,00000000666031606064006060600060000060606060606300 [1502] 4, 1,2014,60600000606060606000006060606060000060606060600000 [1632] 4,0,2015,0080666F6D723800767C717B750072696867346C746B756A63 [1641] 4,1,2015,69656E6363006522000063697E6B416D007067696768000000 [1372] 跨度>

标签: sql sql-server database tsql report


【解决方案1】:

我没有从您的示例中获得足够具体的数据,但一般来说,您可以使用 JOIN 执行基于集合的 UPDATE 来完成这种没有循环和快速性能的行为。让我做一个简单的例子来演示。

CREATE TABLE Products
(ProductID int
,Name varchar(30)
,Price money)

CREATE TABLE NewPrices
(ProductID int
,Price money)

为了帮助可视化,首先在它们之间编写一个连接,以并排查看新旧价格:

SELECT p.ProductID, p.Name, p.Price as OriginalPrice, n.Price as NewPrice
FROM Products as p
JOIN NewPrices as n on p.ProductID = n.ProductID

OK 足够简单的加入,您可以并排查看价格。现在只需将 SELECT 更改为 UPDATE 但保留 FROM 和 JOIN 如下:

UPDATE p
SET Price = n.Price
FROM Products as p
JOIN NewPrices as n on p.ProductID = n.ProductID

这将匹配 ProductID 表中的每条记录,并使用 n 表中匹配行中的值更新 p 表中的值,即 Products。

基本上,FROM 语句与 C 语言中的 FOR 语句相同,SELECT 语句类似于 PRINT 语句。所以 FROM & JOIN 正在执行 WHILE 语句的循环。不是执行 SELECT,而是更新两个表的 JOIN 的每一行。

一旦你掌握了这一点,看看 SQL Server 中的 MERGE 语句,并探索它有什么魔力。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-05-10
    • 1970-01-01
    • 2015-04-18
    • 1970-01-01
    • 2015-05-19
    • 1970-01-01
    • 2014-03-09
    相关资源
    最近更新 更多