1

次のクエリがあります。このクエリは、select 句でサブクエリを複数回使用します。

SELECT DISTINCT CAST(decCostFactor as decimal(9,4)) 
          FROM tblsubteam WITH (NOLOCK) 
          WHERE intstore = st.intStore 
          AND strsubteam = SUBSTRING(tblDetail.strMiscText,12,4)

このサブクエリを削除したい。group by CAST(decCostFactor as decimal(9,4)) を使用してみましたが、今では group by cluase に他の列も含めるように求められます。

どんな助けでも本当に感謝しています。

主なクエリは

DECLARE @Region int=10006

SELECT 
    st.strRegion,
    st.intStore,
    st.strStoreName,
    tblSticker.intStickerNo ,
    tblSticker.strTeamNo AS strTeam ,
    tblSticker.dtmFixtureStartDate AS dtmStartDate ,
    tblSticker.intAreaNo ,
    SUBSTRING ( tblSticker.strMiscText , 8 , 30 ) AS strSection ,
    tblDetail.intLineNum ,
    tblDetail.strBarcode ,
    tblDetail.intBarcodeLength ,
    tblDetail.intBarcodeType ,
    tblDetail.strBarcodeEntrySw AS strKeyBarcode ,
    tblDetail.fltPrice AS fltPrice ,
    tblDetail.fltQty AS fltQty ,
    tblDetail.strPTCCode4 AS strKeyPrice ,
    tblDetail.strPTCCode5 AS strKeyQty ,
    SUBSTRING ( tblDetail.strMiscText , 1 , 1 ) AS strNOF ,
    SUBSTRING ( tblDetail.strClientText , 1 , 30 ) AS strDesc ,
    SUBSTRING ( tblDetail.strMiscText , 12 , 4 ) AS strSubTeam ,
    SUBSTRING ( tblDetail.strMiscText , 16 , 25 ) AS strSubTeamDesc ,
    SUBSTRING ( tblDetail.strClientText , 34 , 3 ) AS strSubDept ,
    SUBSTRING ( tblDetail.strClientText , 37 , 3 ) AS strClass ,
    SUBSTRING ( tblDetail.strClientText , 40 , 3 ) AS strSubClass ,
    SUBSTRING ( tblDetail.strMiscText , 41 , 7 ) AS strCostFactor ,
    SUBSTRING ( tblDetail.strMiscText , 41 , 1 ) AS strPerishableFlag ,
    tblSubTeam.blnBreakoutCost,
    fltPriceLb = tblDetail.fltClientMisc1,
    fltCostLb = CASE 
      WHEN tblDetail.decCost > 0
          THEN tblDetail.decCost
          ELSE tblDetail.fltClientMisc1 *
        ( SELECT DISTINCT CAST(decCostFactor as decimal(6,4)) 
          FROM tblsubteam WITH (NOLOCK) 
          WHERE intstore = st.intStore 
          AND strsubteam = SUBSTRING(tblDetail.strMiscText,12,4) 
        )
          END,
      strVendor = CASE WHEN tblDetail.strVendor IS NULL THEN 'NA' ELSE tblDetail.strVendor END,

    fltWeightSouth = CASE 
      WHEN tblDetail.fltClientMisc1 > 0
        THEN (tblDetail.fltPrice / tblDetail.fltClientMisc1)
        WHEN SUBSTRING(tblDetail.strMiscText,49,1) <> 'R' 
      AND  tblDetail.fltClientMisc1 = 0 
      THEN cast(SUBSTRING(tblDetail.strClientText,43,6) as float)
        ELSE 0 
      END,

    fltCostSouth = ISNULL(CASE 
      WHEN SUBSTRING(tblDetail.strMiscText,50,1) = 'C' 
      THEN (tblDetail.fltPrice ) 
            ELSE
        -- To calculate cost for Subteam 3100 in the south region -  Thomas - 2/19/2008
                CASE 
        WHEN (SUBSTRING(tblDetail.strMiscText,12,4) = '3100') 
        AND (Substring(tblDetail.strMiscText,1,1) <> 'N')
                THEN fltprice  * 
          ( SELECT DISTINCT CAST(decCostFactor as decimal(6,4)) 
            FROM tblsubteam WITH (NOLOCK) 
            WHERE intstore = st.intStore 
            AND strsubteam = SUBSTRING(tblDetail.strMiscText, 12, 4)
          )
                ELSE CASE 
          WHEN tblDetail.fltClientMisc1 > 0 and tblDetail.decCost > 0
                  -- modified by TA to remedy Extended Retail for weighted items
                  THEN (tblDetail.fltPrice / tblDetail.fltClientMisc1) * tblDetail.decCost 
                  ELSE CASE
                        WHEN (Substring(tblDetail.strMiscText,1,1) = 'N')  
            Or   (tblDetail.strBarcode = '00000000000000')
                        THEN CASE 
              WHEN (fltprice = 0 and tblDetail.decCost > 0) 
              THEN CASE 
                WHEN SUBSTRING(tblDetail.strClientText,43,6) <> '' 
                THEN CASE 
                  WHEN CAST(SUBSTRING(tblDetail.strClientText,43,6) as float) > 0 
                                    THEN CAST(SUBSTRING(tblDetail.strClientText,43,6) as float)*tblDetail.decCost 
                                    ELSE fltTotalUnits*tblDetail.decCost
                                  END
                                ELSE 0 * tblDetail.decCost
                                END
                            ELSE CASE 
                WHEN (Substring(tblDetail.strMiscText,41,7)) = ''
                                THEN fltprice * 0 
                                ELSE fltprice  * Cast(Substring(tblDetail.strMiscText,41,7) as decimal(6,4)) 
                                END
                            END
                        ELSE CASE 
              WHEN (fltprice > 0 and tblDetail.decCost = 0) 
                            THEN  fltprice  * 
                ( SELECT DISTINCT CAST(decCostFactor as decimal(6,4)) 
                  FROM tblsubteam WITH (NOLOCK) 
                  WHERE intstore = st.intStore 
                  AND strsubteam = SUBSTRING(tblDetail.strMiscText,12,4)
                )
                            ELSE CASE 
                WHEN (fltprice = 0 and tblDetail.decCost > 0) 
                THEN CASE 
                  WHEN CAST(SUBSTRING(tblDetail.strClientText,43,6) as float) > 0 
                                    THEN CAST(SUBSTRING(tblDetail.strClientText,43,6) as float) * tblDetail.decCost 
                                    ELSE tblDetail.decCost 
                                    END
                              ELSE tblDetail.decCost 
                                END
                            END
            END
          END
        END
      END,0),

  fltItemCost = ISNULL(CASE
    WHEN ((((Substring(tblDetail.strMiscText,41,7) = '00.0000') 
            or (tblDetail.fltClientMisc1 = 0)) 
            or (tblDetail.decCost = 0)) 
            and Substring(tblDetail.strMiscText,1,1) <> 'N') 
        THEN CASE 
      WHEN (fltprice > 0 and tblDetail.decCost = 0) 
            THEN  fltprice * 
        ( SELECT DISTINCT CAST(decCostFactor as decimal(9,4)) 
          FROM tblsubteam WITH (NOLOCK) 
          WHERE intstore = st.intStore 
          AND strsubteam = SUBSTRING(tblDetail.strMiscText,12,4)
        )   
            ELSE CASE 
        WHEN (fltprice = 0 and tblDetail.decCost > 0) 
                THEN tblDetail.decCost
                ELSE CASE 
          WHEN  (Substring(tblDetail.strMiscText,41,7)) = ''
                    THEN  fltprice * 0
                    ELSE fltprice  * Cast(Substring(tblDetail.strMiscText,41,7) as decimal(9,4)) 
                    END
                END
            END
            ELSE CASE 
        WHEN (Substring(tblDetail.strMiscText,1,1) = 'N') 
        Or   (tblDetail.strBarcode = '00000000000000')
                THEN fltprice * Cast(Substring(tblDetail.strMiscText,41,7) as decimal(9,4)) 
                ELSE CASE 
          WHEN (fltprice > 0 and tblDetail.decCost = 0) 
                    THEN  fltprice  * 
            ( SELECT DISTINCT CAST(decCostFactor as decimal(9,4)) 
              FROM tblsubteam WITH (NOLOCK) 
              WHERE intstore = st.intStore 
              AND strsubteam = SUBSTRING(tblDetail.strMiscText,12,4)
            )   
                    ELSE CASE 
            WHEN (Substring(tblDetail.strMiscText,41,7)) = ''
                        THEN fltprice * 0
                        ELSE fltprice  * Cast(Substring(tblDetail.strMiscText,41,7) as decimal(9,4)) 
                      END
                    END
                END
      END, 0),
      strWeight = SUBSTRING(tblDetail.strClientText, 43, 6)

FROM
tblSticker WITH ( NOLOCK )
INNER JOIN tblDetail WITH ( NOLOCK )
ON tblSticker.intStore = tblDetail.intStore
   AND tblSticker.intStickerNo = tblDetail.intStickerNo
   AND tblSticker.dtmStickerDate = tblDetail.dtmStickerDate
LEFT OUTER JOIN tblsubteam
ON tblDetail.intStore = tblSubTeam.intStore
   AND SUBSTRING ( tblDetail.strMiscText , 12 , 4 ) = tblSubTeam.strSubTeam
inner join tblStore st on st.intStore=tblDetail.intStore
--fix add join to store.  Kevin 2/8/07

-- AND SUBSTRING ( tblDetail.strMiscText , 12 , 4 ) = tblSubTeam.strSubTeam
--fix fix move join to store outside of compound conditional.  Eddie 9/2/11
WHERE
   ((@Region is not null and st.intRegion=@Region) or @Region is  null)
    AND st.intStore < 90000
    AND ( tblSticker.intStickerNo NOT BETWEEN 334717100
          AND 334717299 )
    AND tblSticker.strRescanSW = 'N'
    AND ( tblSticker.strEmptyStatus = ' '
          OR tblSticker.strEmptyStatus = '*' )
ORDER BY st.strStoreName,
    tblSticker.intStickerNo ,
    tblDetail.intLineNum
4

2 に答える 2

4

クエリをAPPLYに移動できます。これにより、クエリが 1 回だけ実行されるようになります。

あなたの例は次のようになると思います:

FROM    tblSticker WITH ( NOLOCK )
        INNER JOIN tblDetail WITH ( NOLOCK )
            ON tblSticker.intStore = tblDetail.intStore
            AND tblSticker.intStickerNo = tblDetail.intStickerNo
            AND tblSticker.dtmStickerDate = tblDetail.dtmStickerDate
        LEFT OUTER JOIN tblsubteam
            ON tblDetail.intStore = tblSubTeam.intStore
            AND SUBSTRING ( tblDetail.strMiscText , 12 , 4 ) = tblSubTeam.strSubTeam
        INNER JOIN tblStore st 
            ON st.intStore=tblDetail.intStore
        OUTER APPLY
        (   SELECT  DeCostFactor = CAST(decCostFactor AS DECIMAL(9,4)) 
            FROM    tblsubteam WITH (NOLOCK) 
            WHERE   intstore = st.intStore 
            AND     strsubteam = SUBSTRING(tblDetail.strMiscText,12,4)
        ) dcf

次に、サブクエリの代わりに、単に参照できますdcf.DeCostFactor

一般的なテストとして、以下を使用しました。これは、単一の APPLY と比較して、相関サブクエリを 4 回実行するだけです。

SET STATISTICS IO ON;

WITH T AS
(   SELECT  A = Number, B = Number + 1
    FROM    Master..spt_values
    WHERE   Type = 'P'
)
SELECT  T.A,
        T.B,
        SubQuery = (SELECT T2.B FROM T T2 WHERE T2.A = T.B),
        SubQuery2 = (SELECT T2.B FROM T T2 WHERE T2.A = T.B),
        SubQuery3 = (SELECT T2.B FROM T T2 WHERE T2.A = T.B),
        SubQuery4 =  (SELECT T2.B FROM T T2 WHERE T2.A = T.B)
FROM    T;


-- USING OUTER APPLY
WITH T AS
(   SELECT  A = Number, B = Number + 1
    FROM    Master..spt_values
    WHERE   Type = 'P'
)
SELECT  T.A,
        T.B,
        SubQuery = SubQuery.B,
        SubQuery2 = SubQuery.B,
        SubQuery3 = SubQuery.B,
        SubQuery4 = SubQuery.B
FROM    T
        OUTER APPLY
        (   SELECT  T2.B
            FROM    T T2
            WHERE   T2.A = T.B
        ) SubQuery;

THE IO統計は、それ自体を物語っています。

複数のサブクエリ

Table 'spt_values'. Scan count 8193, logical reads 24625, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

外部適用

Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'spt_values'. Scan count 2, logical reads 18, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

編集

サブクエリはまったく必要ないと思います。tblSubteam同じ基準ですでにテーブルに参加しています。

LEFT OUTER JOIN tblsubteam
    ON tblDetail.intStore = tblSubTeam.intStore
    AND SUBSTRING ( tblDetail.strMiscText , 12 , 4 ) = tblSubTeam.strSubTeam

tblsubteam.DeCostFactorサブクエリの代わりに使用できないのはなぜですか?

于 2013-09-09T12:22:00.120 に答える
1

selectこれを句のサブクエリとして使用します。したがって、1 つの値を返す必要があります。したがって、次のように置き換えることができます。

    ( SELECT top 1 CAST(decCostFactor as decimal(6,4)) 
      FROM tblsubteam WITH (NOLOCK) 
      WHERE intstore = st.intStore 
      AND strsubteam = SUBSTRING(tblDetail.strMiscText,12,4) 
    )

SQL Server は最適化に関して非常に優れています。ただし、distinct問題が発生する可能性があります。個別の値を削除して任意の値を取得すると、最適化が改善される場合があります。

ただし、確認する方法は、実行計画を見ることです。

にインデックスを付けることで、パフォーマンスが向上する可能性がありますtblsubteam(instore, strsubteam, decCostFactor)

于 2013-09-09T12:10:00.123 に答える