如何优化SQL查询以实现最短的执行时间

时间:2013-05-08 08:17:58

标签: sql sql-server-2008 tsql stored-procedures

我有一个简单的表'TABLE_1'

Org   Customer   Code   Ordered   Deleted   Confirmed

RU     Cust_1      A      1000       800        200 
RU     Cust_2      B      300        0          300
US     Cust_3      C      800        100        700
RU     Cust_4      B      100        100        0
US     Cust_5      C      400        200        200 
RU     Cust_6      B      500        300        200   

现在我需要为这些行转换此表,其中'已删除'<> 0喜欢

Org   Code    Customers          Ordered   Confirmed 

RU     A      Cust_1               1000       200
RU     B      Cust_4, Cust_6       600        200
US     C      Cust_3, Cust_5       1200       900

我正在使用以下查询和功能

SELECT T1.Org,
       T1.Code,
       dbo.FUNC(T1.Code, T1.Org) AS 'Customers',
       'Ordered' = (SELECT SUM(Ordered) FROM TABLE_1 AS T2 WHERE T2.Customer = T1.Customer AND T2.Code = T1.Code AND T2.Deleted<>0),
       'Confirmed' = (SELECT SUM(Confirmed) FROM TABLE_1 AS T3 WHERE T3.Customer = T1.Customer AND T3.Code = T1.Code AND T3.Deleted<>0)
FROM TABLE_1 AS T1 
WHERE T1.Deleted <> 0

功能'FUNC':

ALTER FUNCTION [dbo].[FUNC] (@c VARCHAR(MAX), @org VARCHAR(MAX))
RETURNS VARCHAR(MAX) AS BEGIN
DECLARE @p VARCHAR(MAX) ;
SET @p = '' ;
SELECT @p = @p + T1.Customer + ', '
FROM TABLE_1 AS T1
WHERE T1.Code = @c AND T1.Org = @org AND T1.Deleted <> 0
GROUP BY T1.Customer
RETURN SUBSTRING(@p, 1, LEN(@p) - 1)
END

我认为这不是获得结果的最佳方式,特别是如果我有一个大表。 是否有更好的解决方案用于此目的?

修改 表DDL示例

CREATE TABLE [dbo].[TABLE_1](
[Org] [nchar](10) NULL,
[Customer] [nchar](100) NULL,
[Code] [nchar](10) NULL,
[Ordered] [decimal](18,1) NULL,
[Deleted] [decimal](18,1) NULL,
[Confirmed] [decimal](18,1) NULL) 
ON [PRIMARY]

4 个答案:

答案 0 :(得分:2)

您将面临RBAR&#34;问题&#34;你选择做什么。 然而,您可能会发现使用FOR XML PATH(&#39;&#39;)+ OUTER APPLY而不是您的函数更好。

如果你不了解这些,我会写一段代码来证明这些用法。 但是你可以先提供你的表DDL(+一些行)。

这是:

SELECT
    T1.Org
    , T1.Code
    , ISNULL(STUFF(F.Customers, 1, 2, ''), '')  AS Customers
    , SUM(T1.Ordered) OVER (PARTITION BY T1.Customer, T1.Code) AS Ordered
    , SUM(T1.Confirmed) OVER (PARTITION BY T1.Customer, T1.Code) AS Confirmed
FROM TABLE_1 AS T1
OUTER APPLY (
    SELECT
        ', ' + T2.Customer
    FROM TABLE_1 AS T2
    WHERE T2.Code = T1.Code
    AND T2.Org = T1.Org
    AND T2.Deleted <> 0
    FOR XML PATH('')
) AS F(Customers)
WHERE T1.Deleted <> 0

答案 1 :(得分:1)

SQLFiddle demo

SELECT
   Org,
   Code,
   STUFF(
      (SELECT ','+Customer
       FROM t WHERE Code=a.Code and Deleted<>0
       FOR XML PATH('')) , 1 , 1 , '' ),
   SUM(ordered),
   SUM(Confirmed) 

FROM 
   t A 
where Deleted<>0
group by ORG,code

答案 2 :(得分:1)

什么是最好的可能需要对您的特定数据进行一些测试,但是为了开始,让我们修复您的原始查询,以获得您在问题中按预期编写的正确结果:

SELECT T1.Org,
       T1.Code,
       dbo.FUNC(T1.Code, T1.Org) AS Customers,
       SUM(Ordered) AS Ordered,
       SUM(Confirmed) AS Confirmed
FROM TABLE_1 AS T1 
WHERE T1.Deleted <> 0
GROUP BY T1.Org, T1.Code

答案 3 :(得分:1)

即使您的客户名称包含XML控件字符,您也可以这样做。

Fiddle Here

SELECT
            t1.[Org],
            t1.[Code],
            STUFF(
                (
                 SELECT
                               ', ' + c.[Customer]
                     FROM
                               [TABLE_1] c
                     WHERE
                               c.[Deleted] <> 0
                         AND
                               c.[Org] = t1.[Org]
                         AND
                               c.[Code] = t1.[Code]
                     ORDER BY
                               c.[Customer]
                     FOR XML PATH (''), TYPE
                 ).value('.', 'varchar(max)'),
                 1,
                 2,
                 '') [Customers],
            SUM(t1.[Ordered]),
            SUM(t1.[Confirmed])
    FROM
            [TABLE_1] t1

    WHERE
            t1.[Deleted] <> 0
    GROUP BY
            t1.[Org],
            t1.[Code];

就性能而言,只做两个查询并担心以后的逗号分隔列表是有意义的。您可以获得相同的信息,但没有字符串聚合的开销,而MSSQL是如此错位而无法实现的。

Fiddle Here

SELECT
            t1.[Org],
            t1.[Code],
            SUM(t1.[Ordered]),
            SUM(t1.[Confirmed])
    FROM
            [TABLE_1] t1

    WHERE
            t1.[Deleted] <> 0
    GROUP BY
            t1.[Org],
            t1.[Code];

SELECT
            t1.[Org],
            t1.[Code],
            t1.[Customer]
    FROM
            [TABLE_1] t1

    WHERE
            t1.[Deleted] <> 0
    ORDER BY
            t1.[Org],
            t1.[Code],
            t1.[Customer];