Sql-Server

任何類似於 where 1=0 的 SQL where 子句性能

  • January 19, 2016

(我使用的是 SQL Server 2008R2 或更高版本)

為了集中管理和一致,有一個視圖定義如下:

CREATE VIEW view_all_situation
(
 select null as src, tf.col1, sum(col2) as fee, sum(isnull(v1.col1, 0)) as fee1 ...
 from table_fee tf
 inner join parameter_table pt on tf.id = pt.id
 left join view1 v1 on ...
 left join view2 v2 on ...
 where pt.col1 = 0
 group by tf.col1

 UNION ALL

 select tfd.src, tfd.col1, sum(col2) as fee, sum(isnull(v1.col1, 0)) as fee1 ...
 from table_fee_detail tfd
 inner join parameter_table pt on tfd.id = pt.id
 left join view1 v1 on ...
 left join view2 v2 on ...
 where pt.col1 = 1
 group by tfd.col1
)
(Note: parameter_table only have 1 row)

因此,如果 parameter_table.col1 = 1 中的值則返回 table_fee_detail 否則返回 table_fee。(注:parameter_table 只有 1 行)

由於第一部分需要 10 秒,第二部分需要另外 10 秒,最後返回需要 20 秒。如果有更快的方法讓 SQL Server 根據 parameter_table 值執行 UNION ALL 的任一部分,以便它在 10 秒內返回?

由於動態 SQL 不適用於我的情況,我無法建構它來獲得結果。

我試過用

where EXISTS (select 1 from parameter_table where col1 = 0) and 
where EXISTS (select 1 from parameter_table where col1 = 1) 

作為 where 子句,它不能使 SQL Server 在 10 秒內返回。它仍然使用 20 秒。

是否有可能有類似結果的 SQL

where 1=0 

以便 SQL Server 在 10 秒內返回結果?

For example, 
if parameter_table.col1 = 0, i get result from table_fee
Src     col1   fee   fee1
--------------------------------------------
null    USD    100   150
null    EUR    200   150
null    AUD    300   200


if parameter_table.col1 = 1, I get result from table_fee_detail
Src     col1   fee   fee1
--------------------------------------------
USA     USD    100   150
GER     EUR    200   150
AU      AUD    300   200

您正在尋找動態地從兩個表之一中選擇行。這通常可以在沒有動態 SQL 的情況下實現。

為了展示,這裡是一個基於AdventureWorks 範例數據庫的簡化版本:

這個想法是根據Parameter表中**UseArchive列的值從每個Product的**TransactionHistoryTransactionHistoryArchive表中選擇行:

CREATE TABLE dbo.Parameter
(
   ProductID integer NOT NULL PRIMARY KEY,
   UseArchive bit NOT NULL
);

INSERT dbo.Parameter
   (ProductID, UseArchive)
VALUES
   (1, 0),
   (2, 0),
   (3, 1),
   (4, 0);

此範例指定產品 1、2 和 4 的行應來自 TransactionHistory。對於產品 3,行應來自**TransactionHistoryArchive

解決方案:

SELECT 
   P.Name, 
   CA.TransactionID
FROM Production.Product AS P
JOIN dbo.Parameter AS PTR
   ON PTR.ProductID = P.ProductID
CROSS APPLY
(
   SELECT TH.ProductID, TH.TransactionID
   FROM Production.TransactionHistory AS TH
   WHERE 
       TH.ProductID = P.ProductID
       AND PTR.UseArchive = 0

   UNION ALL

   SELECT THA.ProductID, THA.TransactionID
   FROM Production.TransactionHistoryArchive AS THA
   WHERE 
       THA.ProductID = P.ProductID
       AND PTR.UseArchive = 1
) AS CA;

此查詢的執行計劃是:

計劃

這裡的關鍵是應用內部的外部引用PTR.UseArchive = value。這允許優化器建構一個具有啟動表達式的過濾器的計劃。例如,TransactionHistory表 Index Seek 上方的 Filter 有:

過濾謂詞

當然,另一個 seek 上方的 Filter Predicate 非常相似,但會測試UseArchive = 1

每個過濾謂詞對每個產品進行一次評估。它確定計劃中它下面的查找是否將在嵌套循環連接的迭代中執行。

在這個例子中,效果是TransactionHistory index seek執行了3次;TransactionHistoryArchive表上的查找只執行一次。

您可能能夠為您的案例實現此模式。

刪除 4 個左連接。您沒有使用他們的數據,也不需要他們。它會減慢一切,特別是如果您沒有正確的 PK 和索引(告訴我們更多資訊)

parameter_table.id 應該是一個 PK 和/或上面有 1 個或 2 個索引,例如(它實際上取決於您的模型):

create index idx_parameter_table_id0 on parameter_table(id) where col1 = 0
create index idx_parameter_table_id1 on parameter_table(id) where col1 = 1

要麼

create index idx_parameter_table_id1 on parameter_table(col1, id)

如果 col2 來自 parameter_table,則將其包含在索引中可能會很有用:

create index ... on parameter_table(...) include (col2)

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