2014-03-07 73 views
2

我有一個自定義商店網站,當他/她按下購買按鈕時,使用一組規則(更準確地說是7)來爲用戶定位零件。有些規則是這樣的:什麼性能更好:UNION查詢和separete查詢的一堆?

  • 查找第一銷售者在同一國家,市,區爲消費者(每區只有一個賣家是允許的)
  • 如果賣方上面沒有部分,得到與上述同一組的賣家,並在同一城市
  • 如果上述賣家沒有該零件,得到一個賣家在同一城市
  • 等等。 。

我已經制定了一個ser並且每個規則的巨大聯盟中有大約300行SQL(格式化爲便於閱讀),只有第一個結果才能找到。

我不確定這是更好的事情要做還是更好地做7順序檢查有條件的往返行程,如果後面的一個在調用下一個結果之前有結果。

我估計大部分用戶都會經歷規則4,即SQL Server的4次往返,只是爲了得到一個部分,並且巨型聯合查詢的結果在不到一秒內返回,少於100,000個部分表。

問題是,如果這個網站開始在可用部件和用戶的溫度下長大,那麼最好是讓SQL Server處理帶有巨大查詢的工作,該查詢只返回我在一次旅行中需要的或者更好調用單獨的查詢?

我們使用傳統的ASP來完成這項工作(是的,老學校,你知道嗎?)如果這在任何情況下都是相關的。

讓我知道你是否需要查看查詢本身。

編輯:

只是爲了總之,這裏是我現在使用的查詢:

SELECT TOP 1 regras.ids, regras.idCadastro, regras.regra, e.descricao AS nomeEstado, cd.descricao AS nomeCidade, b.nome AS nomeBairro 
FROM ( 
    SELECT dbo.group_concat(idPecaItem) AS ids, idCadastro, '1' AS regra 
    FROM ( 
     SELECT TOP 2 idPecaItem, idCadastro 
     FROM pecasItens 
     WHERE COALESCE(pecasItens.idCadastro, 0) = (CASE WHEN EXISTS( 
      SELECT TOP 1 COALESCE(pi.idCadastro, 0) 
      FROM pecasItens pi 
      LEFT JOIN cadastros c ON pi.idCadastro = c.idCadastro 
      WHERE (pi.idCadastro IS NULL OR c.tipoParceiro = 'c') AND idPeca = 31740 AND idPedidoItem IS NULL AND dataEntrada <= '2014-3-13' AND devolucaoSolicitada IS NULL 
      GROUP BY pi.idCadastro 
      HAVING COUNT(pi.idPecaItem) >= 2 
     ) THEN ( 
      SELECT TOP 1 COALESCE(pi.idCadastro, 0) 
      FROM pecasItens pi 
      LEFT JOIN cadastros c ON pi.idCadastro = c.idCadastro 
      WHERE (pi.idCadastro IS NULL OR c.tipoParceiro = 'c') AND idPeca = 31740 AND idPedidoItem IS NULL AND dataEntrada <= '2014-3-13' AND devolucaoSolicitada IS NULL 
      GROUP BY pi.idCadastro 
      HAVING COUNT(pi.idPecaItem) >= 2 
     ) ELSE NULL END) 
     AND idPeca = 31740 AND idPedidoItem IS NULL AND dataEntrada <= '2014-3-13' AND devolucaoSolicitada IS NULL 
    ) regra1 
    GROUP BY idCadastro 

    UNION 

    SELECT dbo.group_concat(idPecaItem) AS ids, idCadastro, '2' AS regra 
    FROM ( 
     SELECT TOP 2 idPecaItem, idCadastro 
     FROM pecasItens 
     WHERE COALESCE(pecasItens.idCadastro, 0) = (CASE WHEN EXISTS( 
      SELECT TOP 1 COALESCE(pi.idCadastro, 0) 
      FROM pecasItens pi 
      LEFT JOIN cadastros c ON pi.idCadastro = c.idCadastro AND c.tipoParceiro = 'r' AND c.idCadastroGrupo = 1 
      WHERE pi.idCadastro IS NOT NULL AND idPeca = 31740 AND idPedidoItem IS NULL AND dataEntrada <= '2014-3-13' AND devolucaoSolicitada IS NULL 
      GROUP BY pi.idCadastro 
      HAVING COUNT(pi.idPecaItem) >= 2 
     ) THEN ( 
      SELECT TOP 1 COALESCE(pi.idCadastro, 0) 
      FROM pecasItens pi 
      LEFT JOIN cadastros c ON pi.idCadastro = c.idCadastro AND c.tipoParceiro = 'r' AND c.idCadastroGrupo = 1 
      WHERE pi.idCadastro IS NOT NULL AND idPeca = 31740 AND idPedidoItem IS NULL AND dataEntrada <= '2014-3-13' AND devolucaoSolicitada IS NULL 
      GROUP BY pi.idCadastro 
      HAVING COUNT(pi.idPecaItem) >= 2 
     ) ELSE NULL END) 
     AND idPeca = 31740 AND idPedidoItem IS NULL AND dataEntrada <= '2014-3-13' AND devolucaoSolicitada IS NULL 
    ) regra2 
    GROUP BY idCadastro 

    UNION 

    SELECT dbo.group_concat(idPecaItem) AS ids, idCadastro, '3' AS regra 
    FROM ( 
     SELECT TOP 2 idPecaItem, idCadastro 
     FROM pecasItens 
     WHERE COALESCE(pecasItens.idCadastro, 0) = (CASE WHEN EXISTS( 
      SELECT TOP 1 COALESCE(pi.idCadastro, 0) 
      FROM pecasItens pi 
      LEFT JOIN cadastros c ON pi.idCadastro = c.idCadastro AND c.tipoParceiro = 'r' AND c.idCadastroGrupo = 1 
      INNER JOIN cadastrosCidades cc ON c.idCadastro = cc.idCadastro AND cc.idCidade = 4850 
      WHERE pi.idCadastro IS NOT NULL AND idPeca = 31740 AND idPedidoItem IS NULL AND dataEntrada <= '2014-3-13' AND devolucaoSolicitada IS NULL 
      GROUP BY pi.idCadastro 
      HAVING COUNT(pi.idPecaItem) >= 2 
     ) THEN ( 
      SELECT TOP 1 COALESCE(pi.idCadastro, 0) 
      FROM pecasItens pi 
      LEFT JOIN cadastros c ON pi.idCadastro = c.idCadastro AND c.tipoParceiro = 'r' AND c.idCadastroGrupo = 1 
      INNER JOIN cadastrosCidades cc ON c.idCadastro = cc.idCadastro AND cc.idCidade = 4850 
      WHERE pi.idCadastro IS NOT NULL AND idPeca = 31740 AND idPedidoItem IS NULL AND dataEntrada <= '2014-3-13' AND devolucaoSolicitada IS NULL 
      GROUP BY pi.idCadastro 
      HAVING COUNT(pi.idPecaItem) >= 2 
     ) ELSE NULL END) 
     AND idPeca = 31740 AND idPedidoItem IS NULL AND dataEntrada <= '2014-3-13' AND devolucaoSolicitada IS NULL 
    ) regra3 
    GROUP BY idCadastro 
    UNION 

    SELECT dbo.group_concat(idPecaItem) AS ids, idCadastro, '4' AS regra 
    FROM ( 
     SELECT TOP 2 idPecaItem, idCadastro 
     FROM pecasItens 
     WHERE COALESCE(pecasItens.idCadastro, 0) = (CASE WHEN EXISTS( 
      SELECT TOP 1 COALESCE(pi.idCadastro, 0) 
      FROM pecasItens pi 
      INNER JOIN cadastros c ON pi.idCadastro = c.idCadastro AND c.tipoParceiro = 'r' 
      INNER JOIN cadastrosGrupos cg ON c.idCadastroGrupo = cg.idCadastroGrupo AND cg.idMarca = 2 
      INNER JOIN cadastrosCidades cc ON c.idCadastro = cc.idCadastro AND cc.idCidade = 4850 
      WHERE pi.idCadastro IS NOT NULL AND idPeca = 31740 AND idPedidoItem IS NULL AND dataEntrada <= '2014-3-13' AND devolucaoSolicitada IS NULL 
      GROUP BY pi.idCadastro 
      HAVING COUNT(pi.idPecaItem) >= 2 
     ) THEN ( 
      SELECT TOP 1 COALESCE(pi.idCadastro, 0) 
      FROM pecasItens pi 
      INNER JOIN cadastros c ON pi.idCadastro = c.idCadastro AND c.tipoParceiro = 'r' 
      INNER JOIN cadastrosGrupos cg ON c.idCadastroGrupo = cg.idCadastroGrupo AND cg.idMarca = 2 
      INNER JOIN cadastrosCidades cc ON c.idCadastro = cc.idCadastro AND cc.idCidade = 4850 
      WHERE pi.idCadastro IS NOT NULL AND idPeca = 31740 AND idPedidoItem IS NULL AND dataEntrada <= '2014-3-13' AND devolucaoSolicitada IS NULL 
      GROUP BY pi.idCadastro 
      HAVING COUNT(pi.idPecaItem) >= 2 
     ) ELSE NULL END) 
     AND idPeca = 31740 AND idPedidoItem IS NULL AND dataEntrada <= '2014-3-13' AND devolucaoSolicitada IS NULL 
    ) regra4 
    GROUP BY idCadastro 

    UNION 

    SELECT dbo.group_concat(idPecaItem) AS ids, idCadastro, '5' AS regra 
    FROM ( 
     SELECT TOP 2 idPecaItem, idCadastro 
     FROM pecasItens 
     WHERE COALESCE(pecasItens.idCadastro, 0) = (CASE WHEN EXISTS( 
      SELECT TOP 1 COALESCE(pi.idCadastro, 0) 
      FROM pecasItens pi 
      INNER JOIN cadastrosGrupos cg ON pi.idCadastro = cg.idCadastroMontadora AND cg.idCadastroGrupo = 1 
      WHERE pi.idCadastro IS NOT NULL AND idPeca = 31740 AND idPedidoItem IS NULL AND dataEntrada <= '2014-3-13' AND devolucaoSolicitada IS NULL 
      GROUP BY pi.idCadastro 
      HAVING COUNT(pi.idPecaItem) >= 2 
     ) THEN ( 
      SELECT TOP 1 COALESCE(pi.idCadastro, 0) 
      FROM pecasItens pi 
      INNER JOIN cadastrosGrupos cg ON pi.idCadastro = cg.idCadastroMontadora AND cg.idCadastroGrupo = 1 
      WHERE pi.idCadastro IS NOT NULL AND idPeca = 31740 AND idPedidoItem IS NULL AND dataEntrada <= '2014-3-13' AND devolucaoSolicitada IS NULL 
      GROUP BY pi.idCadastro 
      HAVING COUNT(pi.idPecaItem) >= 2 
     ) ELSE NULL END) 
     AND idPeca = 31740 AND idPedidoItem IS NULL AND dataEntrada <= '2014-3-13' AND devolucaoSolicitada IS NULL 
    ) regra5 
    GROUP BY idCadastro 

    UNION 

    SELECT dbo.group_concat(idPecaItem) AS ids, idCadastro, '6' AS regra 
    FROM ( 
     SELECT TOP 2 idPecaItem, idCadastro 
     FROM pecasItens 
     WHERE COALESCE(pecasItens.idCadastro, 0) = (CASE WHEN EXISTS( 
      SELECT TOP 1 COALESCE(pi.idCadastro, 0) 
      FROM pecasItens pi 
      LEFT JOIN cadastros c ON pi.idCadastro = c.idCadastro AND c.tipoParceiro = 'r' AND c.idEstado = 25 AND c.atendeEstadoTodo = 1 
      WHERE pi.idCadastro IS NOT NULL AND idPeca = 31740 AND idPedidoItem IS NULL AND dataEntrada <= '2014-3-13' AND devolucaoSolicitada IS NULL 
      GROUP BY pi.idCadastro 
      HAVING COUNT(pi.idPecaItem) >= 2 
     ) THEN ( 
      SELECT TOP 1 COALESCE(pi.idCadastro, 0) 
      FROM pecasItens pi 
      LEFT JOIN cadastros c ON pi.idCadastro = c.idCadastro AND c.tipoParceiro = 'r' AND c.idEstado = 25 AND c.atendeEstadoTodo = 1 
      WHERE pi.idCadastro IS NOT NULL AND idPeca = 31740 AND idPedidoItem IS NULL AND dataEntrada <= '2014-3-13' AND devolucaoSolicitada IS NULL 
      GROUP BY pi.idCadastro 
      HAVING COUNT(pi.idPecaItem) >= 2 
     ) ELSE NULL END) 
     AND idPeca = 31740 AND idPedidoItem IS NULL AND dataEntrada <= '2014-3-13' AND devolucaoSolicitada IS NULL 
    ) regra6 
    GROUP BY idCadastro 

    UNION 

    SELECT dbo.group_concat(idPecaItem) AS ids, idCadastro, '7' AS regra 
    FROM ( 
     SELECT TOP 2 idPecaItem, idCadastro 
     FROM pecasItens 
     WHERE COALESCE(pecasItens.idCadastro, 0) = (CASE WHEN EXISTS( 
      SELECT TOP 1 COALESCE(pi.idCadastro, 0) 
      FROM pecasItens pi 
      LEFT JOIN cadastros c ON pi.idCadastro = c.idCadastro AND c.tipoParceiro = 'r' AND c.atendeBrasilTodo = 1 
      WHERE pi.idCadastro IS NOT NULL AND idPeca = 31740 AND idPedidoItem IS NULL AND dataEntrada <= '2014-3-13' AND devolucaoSolicitada IS NULL 
      GROUP BY pi.idCadastro 
      HAVING COUNT(pi.idPecaItem) >= 2 
     ) THEN ( 
      SELECT TOP 1 COALESCE(pi.idCadastro, 0) 
      FROM pecasItens pi 
      LEFT JOIN cadastros c ON pi.idCadastro = c.idCadastro AND c.tipoParceiro = 'r' AND c.atendeBrasilTodo = 1 
      WHERE pi.idCadastro IS NOT NULL AND idPeca = 31740 AND idPedidoItem IS NULL AND dataEntrada <= '2014-3-13' AND devolucaoSolicitada IS NULL 
      GROUP BY pi.idCadastro 
      HAVING COUNT(pi.idPecaItem) >= 2 
     ) ELSE NULL END) 
     AND idPeca = 31740 AND idPedidoItem IS NULL AND dataEntrada <= '2014-3-13' AND devolucaoSolicitada IS NULL 
    ) regra7 
    GROUP BY idCadastro 
) regras 
LEFT JOIN cadastros c ON regras.idCadastro = c.idCadastro 
LEFT JOIN listaEstados e ON c.idEstado = e.idEstado 
LEFT JOIN listaCidades cd ON c.idCidade = cd.idCidade 
LEFT JOIN listaBairros b ON c.idBairro = b.idBairro 
ORDER BY regra ASC 

不,這不是MySQL的。 group_concat()這裏是來自這個人的自定義聚合http://groupconcat.codeplex.com/

+0

您如何看待,現在是否有必要查看查詢? – Alexander

+1

對不起。我沒有得到它。英語不是我的母語。我想你很諷刺,並告訴我發佈查詢。是對的,有趣嗎? – rcdmk

+1

小心過早優化(「http://c2.com/cgi/wiki?PrematureOptimization」)!但無論如何,不​​妨考慮一下。以這種方式想想......你有兩個選擇,所以如果它成爲瓶頸,你可以在流程中間切換你的過程。可選性在這裏很好。我傾向於將這些推到一個聯合中,特別是如果底層查詢只能在這種情況下使用。第三種選擇是將過濾的記錄集(Sql很棒)返回到100條左右的記錄,並在代碼中進行決策(並且單元測試您如何做出決定)。 – BlackjacketMack

回答

3

在幾乎所有情況下,RDBMS都處於一個更好的位置,可以讓你成爲第一行。

如果您的查詢看起來像這樣,

SELECT TOP 1 * 
FROM (
    SELECT ... FROM ... -- Query #1 
UNION ALL 
    SELECT ... FROM ... -- Query #2 
UNION ALL 
    ... 
UNION ALL 
    SELECT ... FROM ... -- Query #7 
) 

優化是足夠聰明的停止詢問在什麼是產生你所需要的結果的規則,是它的規則一,規則四或規則七。最重要的是,優化器可以並行運行您的查詢。因爲它離你的數據更近,所以很難想象你可以通過將部分查詢邏輯從你的RDBMS中移走來「超越」它。

+0

謝謝,我就是這麼做的。我很好奇,如果在併發訪問數量增長時這不會影響性能,但不知道優化程序在找到結果時停止。很高興知道。 – rcdmk

+0

您能否澄清我更多?這些查詢按執行順序返回嗎?可以說我有'選擇top 1 * from(選擇x,1作爲q從tbl,其中y = 1聯合選擇x,2作爲q從tbl,其中y = 2)tb order by q asc'。是否需要訂單來保證規則將按順序返回,否則這隻會導致更多的性能損失? – rcdmk

+0

@rcdmk「UNION」的順序不能保證 - 您可以以任意順序獲取數據,對於相同的RDBMS甚至可能不會相同。良好的優化器可以並行運行各個SELECT,因此您可以獲得「贏得比賽」的排名。添加一個ORDER BY'不會改變任何東西,因爲它會應用於查詢的結果,這是一行。 – dasblinkenlight

1

我的傾向是將工作留在SQL中,但重構您的查詢,因此它不是聯合。您應該能夠提供一個存儲過程,一旦找到結果,內部會執行一系列單個查詢。僞SQL將會像這樣開始,並可能在此過程中得到改進。

CREATE PROC GetBestSeller (Part, State, City, District) AS BEGIN 

    DECLARE @Seller INT 

    SELECT TOP 1 @idSeller = idSeller FROM your first choice 

    IF @Seller IS NOT NULL BEGIN 
    SELECT * FROM Seller WHERE idSeller = @idSeller 
    RETURN 
    END 

    SELECT TOP 1 @idSeller = idSeller FROM your second choice 
    SELECT * FROM Seller WHERE idSeller = @idSeller 
    RETURN 
    END 

..and so one 
END 

編輯:@Dasblinkenlight可能有它的權利,在SQL Server的查詢優化器可能會做這樣的事情在內部,你可以看看探查,看看這是什麼真正與發生聯盟。

+0

這是要看的東西。有人對此有比較嗎?我之前想過要問,但我認爲我必須這樣做。 – rcdmk