SQL Server:帮助优化我的查询

时间:2017-04-01 17:41:00

标签: sql-server

C#程序员在这里,我的任务是在我们的一个遗留应用程序中编辑冗长的SQL Server程序,这些程序需要尽可能提高性能和高效运行。如果我的路线最适合当前的情景,我将不胜感激。

SCENARIO

由于原始设计师对代码和DB的设计,这是非正统的。对于搜索网格,我需要查看"保修文档"已根据用户选择的选项以及字符串/单词的串联值"保修"在tbl.docs中生成或未生成。和tbl.warranty.warrantyId值本身。

保修的价值' + tbl.warranty.warrantyId等于tbl.docs.name列值,不幸的是,这是加入/链接两个表的唯一方法。

每次保修可以多次生成保修文档。

参数@IsGenerated是最终用户选择是否参与过滤的用户选项。

这里有一些填充的数据用于说明:

tbl.warranty

| warrantyId | name        | createdDate             | 
|------------|-------------|-------------------------|
| 456        | Warranty 1  | 2002-04-01 12:14:53.330 | 
| 1000       | Warranty 2  | 2002-04-01 12:14:53.327 | 
| 1701       | Warranty 3  | 2002-04-01 12:14:53.333 | 
| 2456       | Warranty 4  | 2002-04-01 12:14:53.327 | 
| 3556       | Warranty 5  | 2002-04-01 12:14:53.330 | 

tbl.docs

| docId      | name         | createdDate             | 
|------------|--------------|-------------------------|
| 1          | Warranty1000 | 2006-11-25 13:33:31.093 | 
| 2          | Warranty456  | 2015-02-11 13:33:31.100 | 
| 3          | Warranty1000 | 2012-05-17 13:33:31.097 | 
| 4          | Warranty1000 | 2017-01-11 13:33:31.097 | 
| 5          | Warranty1701 | 2017-03-14 13:33:31.100 |
| 6          | Warranty456  | 2017-03-15 13:33:31.100 | 

所以你可以看到:

  • warrantyId 1000已生成三次
  • warrantyId 456已生成两次
  • 保修单3556和2456的保修完全没有生成,所以......

期望的行动/结果

用户可以选择不选择任何过滤器选项,[我需要显示所有保修记录和生成的时间(tbl.docs.createdDate),但是返回null tbl.docs.createdDate(如果愿意,还会生成日期)如果它还没有被请求生成,或者基于max tbl.docs.createdDate(generatedDate)的MOST RECENT记录(如果有的话)

 | warrantyId | name         | generatedDate           |
 |------------|--------------|-------------------------|
 | 456        | Warranty 1   | 2017-03-15 13:33:31.100 |
 | 1000       | Warranty 2   | 2017-01-11 13:33:31.097 |
 | 1701       | Warranty 3   | 2017-03-14 13:33:31.100 |
 | 2456       | Warranty 4   | NULL                    |
 | 3556       | Warranty 5   | NULL                    |

用户可以过滤已为其生成文档的保证,[我需要显示所有具有doc生成记录的保修记录,基于字符串/单词"保修"和warrantyId等于docs.name值。生成多个文档的保证,我只需要最近生成的记录]

 | warrantyId | name         | generatedDate           | 
 |------------|--------------|-------------------------|
 | 456        | Warranty 1   | 2017-03-15 13:33:31.100 | 
 | 1000       | Warranty 2   | 2017-01-11 13:33:31.097 | 
 | 1701       | Warranty 3   | 2017-03-14 13:33:31.100 |

用户可以过滤已为其生成文档的保证,[我需要显示所有保修记录,这些保修记录尚未根据字符串/单词生成文档生成的记录"保修和"保修和"保修和"保修& #34;和warrantyId等于docs.name]

 | warrantyId | name         | generatedDate           | 
 |------------|--------------|-------------------------|
 | 2456       | Warranty 4   | NULL                    | 
 | 3556       | Warranty 5   | NULL                    |

这是我的努力。我想根据docs表创建一个临时表,并在我的查询中使用它是效率的最佳途径,而不是将此查询压低,而不是已经存在。

IF OBJECT_ID('tempdb..#tmpDocs') IS NOT NULL 
    DROP TABLE #tmpDocs
GO

CREATE TABLE #tmpDocs
(
    createdDate datetime not null,
    name varchar(30) not null
)

INSERT INTO #tmpDocs (createdDate, name)
    SELECT createdDate, name 
    FROM docs

DECLARE @IsGenerated BIT 
SET @IsGenerated = 0

SELECT 
    w.warrantyId, 
    w.name, 
    (SELECT TOP 1 d.createdDate 
     FROM #tmpDocs d 
     WHERE d.name = CONCAT('Warranty', w.warrantyId) 
     ORDER BY d.createdDate DESC) AS [generatedDate] 
FROM 
    warranty w 
WHERE 
    (@IsGenerated IS NULL OR @IsGenerated = 0 
     OR EXISTS (SELECT * 
                FROM #tmpDocs d 
                WHERE d.name = CONCAT('Warranty', w.warrantyId)))
                  AND (@IsGenerated IS NULL OR @IsGenerated = 1 OR 
                       NOT EXISTS (SELECT * 
                                   FROM #tmpDocs d 
                                   WHERE d.name = CONCAT('Warranty', w.warrantyId)
                      )
               )
      )

已编辑 - ATTEMPT#2

select 
    w.warrantyId, 
    w.name, 
    d.createdDate as [generatedDate] 
from warranty w 
left join #tmpDocs d 
    on d.name = concat('Warranty', w.warrantyId) 
    AND d.createdDate = (SELECT  top 1  d.createdDate 
                      FROM     #tmpDocs d 
                      WHERE d.name = CONCAT('Warranty', w.warrantyId)
                      ORDER BY d.createdDate desc)
WHERE 
    (@IsGenerated IS NULL OR @IsGenerated = 0 
     OR EXISTS (SELECT * 
                FROM #tmpDocs d 
                WHERE d.name = CONCAT('Warranty', w.warrantyId))
    )
    AND (@IsGenerated IS NULL OR @IsGenerated = 1 
    OR NOT EXISTS (SELECT * 
                    FROM #tmpDocs d 
                    WHERE d.name = CONCAT('Warranty', w.warrantyId)
        )
    )
group by w.warrantyId, d.createdDate, w.name

执行时间是相同的,我猜测是因为我的小数据集我正在使用:

(5行(s)受影响)

SQL Server执行时间:    CPU时间= 0 ms,经过时间= 0 ms。

(5行(s)受影响)

SQL Server执行时间:    CPU时间= 0 ms,经过时间= 0 ms。

非常感谢您阅读此内容等。如果有其他途径(不使用CTE,因为这只是proc的一个简单方面,我将进行编辑,我不会有在那个时候重构整个事情的时间),我很乐意听到它。执行此程序不能陷入困境。

1 个答案:

答案 0 :(得分:0)

这绝对不是最佳选择。如果您有任何电源,最佳解决方案是更新doc表并将保修ID添加为单独的列,与保修表的保修ID相同的数据类型。如果这不是一个选项,另一个解决方案是打破两个查询(一个用于文档,一个用于保证),并让应用程序生成IN子句以包含文档名称。

至于在应用程序代码中可以更好地处理的过滤。

以下查询将为您提供所需的内容,但不太确定性能,而实际上无法自行运行对db的查询。

SELECT 
    w.warrantyId, 
    MAX(w.name) as name, 
    MAX(d.createdDate) as generatedDate
FROM warranty w 
LEFT JOIN docs d on d.Name = CONCAT('Warranty', w.warrantyId)
GROUP BY w.warrantyId