2013-09-09 3 views
0

У меня есть следующий запрос, этот запрос использует подзапрос в несколько раз ЗЕЬЕСТА какУдаления подзапроса оператора выбора используется несколько раз, чтобы оптимизировать производительность

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

Я хочу, чтобы удалить этот подзапрос. Я попытался использовать группу с помощью CAST (decCostFactor как десятичный (9,4)), но теперь он просит включить в группу другие столбцы и 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 [email protected]) 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 

ответ

1

У вас есть это как подзапрос в предложении select. Следовательно, он должен вернуть одно значение. Следовательно, вы можете заменить его на:

(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).

4

Вы можете переместить свой запрос на APPLY, это гарантирует, что он будет выполнен только один раз.

Я думаю, что ваш пример стал бы что-то вроде:

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.

В родовом тесте я использовал следующее, что просто выполняет коррелированный подзапрос в 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; 

Ио Статистика говорят сами за себя:

Несколько подзапросов

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. 

EDIT

Я не думаю, что вам нужно подзапросы на всех, вы уже присоединились к столу tblSubteam по тем же критериям:

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

Почему не можете ли вы просто использовать tblsubteam.DeCostFactor вместо подзапроса?

+0

только с помощью tblsubteam.DeCostFactor привел к повторяющимся значениям для Dulicate для DeCostFactor – azim

+0

. Тогда соединение все равно будет вызывать дубликаты, они просто будут скрыты из-за того, что вы не выбираете этот столбец. – GarethD