Sql-Server

從具有多個關係的兩個表中進行選擇的最佳做法是什麼?

  • February 16, 2017

我有兩個具有如下結構的表: 在此處輸入圖像描述 並且正在使用以下查詢選擇數據:

SELECT
(SELECT Name FROM Management_EnumerableItem ME WHERE ME.ID = DN) DN,
(SELECT Name FROM Management_EnumerableItem ME WHERE ME.ID = PN) PN,
(SELECT Name FROM Management_EnumerableItem ME WHERE ME.ID = Winder) Winder,
(SELECT Name FROM Management_EnumerableItem ME WHERE ME.ID = CouplingType) CouplingType,
(SELECT Name FROM Management_EnumerableItem ME WHERE ME.ID = Type) Type,
(SELECT Name FROM Management_EnumerableItem ME WHERE ME.ID = ILayer) ILayer,
(SELECT Name FROM Management_EnumerableItem ME WHERE ME.ID = OLayer) OLayer
FROM Product_Coupling_Serial

那麼,對於這樣的選擇(最快的方式),獲得最佳性能的最佳實踐是什麼?

在 Id 列上創建覆蓋索引並在表 Management_EnumerableItem 上包含名稱。

CREATE INDEX IDX_Name on Management_EnumerableItem (Id) Include (Name) with (fillfactor=90);

並這樣寫。

SELECT A.NAME,
B.NAME,
C.NAME,
D.NAME,
E.NAME,
F.NAME,
G.NAME,

FROM Product_Coupling_Serial P
LEFT OUTER JOIN Management_EnumerableItem A
ON A.ID = P.DN
LEFT OUTER JOIN Management_EnumerableItem B
ON B.ID = P.PN
LEFT OUTER JOIN Management_EnumerableItem C
ON C.ID = P.Winder
LEFT OUTER JOIN Management_EnumerableItem D
ON D.ID = P.CouplingType
LEFT OUTER JOIN Management_EnumerableItem E
ON E.ID = P.[Type]
LEFT OUTER JOIN Management_EnumerableItem F
ON F.ID = P.[ILayer]
LEFT OUTER JOIN Management_EnumerableItem G
ON G.ID = P.[OLayer]

謝謝

請考慮嘗試此查詢,並讓我知道它的執行情況。

WITH EnumerableItemNames AS (
  SELECT
     PcsID = pcs.ID,
     v.ColName,
     ItemName = me.Name
  FROM
     dbo.Product_Coupling_Serial pcs
     CROSS APPLY (VALUES
        ('DN', pcs.DN),
        ('PN', pcs.PN),
        ('Winder', pcs.Winder),
        ('CouplingType', pcs.CouplingType),
        ('Type', pcs.[Type]),
        ('ILayer', pcs.ILayer),
        ('OLayer', pcs.OLayer)
     ) v (ColName, EnumerableItemID)
     LEFT JOIN dbo.Management_EnumerableItem me
        ON v.EnumerableItemID = me.ID
)
SELECT
  p.DN, p.PN, p.Winder, p.CouplingType, p.[Type], p.ILayer, p.OLayer
FROM
  EnumerableItemNames ein
  PIVOT (
     Max(ein.ItemName)
     FOR ein.ColName IN (DN, PN, Winder, CouplingType, [Type], ILayer, OLayer)
  ) p
;

雖然理論上它可能在性能上完全失敗,但我也認為它最終可能會表現得更好。如果不是更好,您仍然可以通過將 CTE 的結果(沒有 LEFT JOIN to Management_EnumerableItem)插入到帶有一些精心選擇的索引的臨時表中,然後使用臨時表進行第二次查詢來獲得它. 它確實有點取決於您查詢表的準確程度、它有多少行、它們有多寬、有多少結果行等等。

如果您需要表中的更多列Product_Coupling_Serial,那麼您可以嘗試在 CTE 中包含這些列,但這可能會通過增加數據透視操作所需的記憶體來嚴重影響性能,因此您也可以在最後加入它:

// CTE here...
SELECT
  pcs.Year,
  pcs.ProductCode,
  pcs.QRText,
  pcs.UniqueSerial,
  ...
  p.DN, p.PN, p.Winder, p.CouplingType, p.[Type], p.ILayer, p.OLayer
FROM
  EnumerableIDs ei
  PIVOT (
     Max(ei.ItemName)
     FOR ei.ColName IN (DN, PN, Winder, CouplingType, [Type], ILayer, OLayer)
  ) p
  INNER JOIN dbo.Product_Coupling_Serial pcs
     ON ei.PcsID = pcs.ID
;

引用自:https://dba.stackexchange.com/questions/162608