我只想基于列的select表中的記錄。本應后在另一個叫表。但是,目前兩個表(客戶端 1 和客戶端 2)中都有 2 個,它們的.StockPostingDatePostingDateInitDateInitClientclientInitDate
根據下面還包含的示例資料,通過下面的代碼,我得到了我目前需要的東西。但是,出現了兩個問題,首先基于數百萬條記錄,查詢花費的時間太長(數小時)。其次,每次包含新客戶時,它根本不是動態的。
解決性能問題的一個潛在選項是撰寫兩個單獨的查詢,一個用于客戶端 1,一個用于客戶端 2 UNION,中間有一個。不幸的是,這還不夠動態,因為可能有多個客戶端。
SELECT
Material
,Stock
,Stock.PostingDate
,Stock.Client
FROM Stock
LEFT JOIN (SELECT InitDate FROM InitClient where Client = 1) C1 ON 1=1
LEFT JOIN (SELECT InitDate FROM InitClient where Client = 2) C2 ON 1=1
WHERE
(
(Stock.Client = 1 AND Stock.PostingDate > C1.InitDate) OR
(Stock.Client = 2 AND Stock.PostingDate > C2.InitDate)
)
示例資料集:
CREATE TABLE InitClient
(
Client varchar(300),
InitDate date
);
INSERT INTO InitClient (Client,InitDate)
VALUES
('1', '5/1/2021'),
('2', '1/31/2021');
SELECT * FROM InitClient
CREATE TABLE Stock
(
Material varchar(300),
PostingDate varchar(300),
Stock varchar(300),
Client varchar(300)
);
INSERT INTO Stock (Material,PostingDate,Stock,Client)
VALUES
('322', '1/1/2021', '5', '1'),
('101', '2/1/2021', '5', '2'),
('322', '3/2/2021', '10', '1'),
('101', '4/13/2021', '5', '1'),
('400', '5/11/2021', '170', '2'),
('401', '6/20/2021', '200', '1'),
('322', '7/20/2021', '160', '2'),
('400', '8/9/2021', '93', '2');
SELECT * FROM Stock
想要的結果,但是用 OR 陳述句的替代品來提高性能:
| Material | PostingDate | Stock | Client |
|----------|-------------|-------|--------|
| 322 | 1/1/2021 | 5 | 1 |
| 101 | 2/1/2021 | 5 | 2 |
| 322 | 3/2/2021 | 10 | 1 |
| 101 | 4/13/2021 | 5 | 1 |
| 400 | 5/11/2021 | 170 | 2 |
| 401 | 6/20/2021 | 200 | 1 |
| 322 | 7/20/2021 | 160 | 2 |
| 400 | 8/9/2021 | 93 | 2 |
如果在上面的代碼中有可能的替代品來保持性能,同時使其動態化,有什么建議嗎?
uj5u.com熱心網友回復:
期望您的查詢是動態的并沒有錯。但是,為了使其性能更高,您可能需要在相互沖突的期望之間達成妥協。我將在此處介紹一些優化查詢的方法,其中一些涉及一些劇烈的更改,但最終由您或您的客戶決定需要如何改進。此外,一些改進可能無效,所以不要想當然,測驗一切。閑話少說,讓我們看看建議
查詢
首先,我會嘗試稍微更改查詢,也許這樣的事情可以幫助您
SELECT
Material
,Stock
,Stock.PostingDate
,C1.InitDate
,C2.InitDate
,Stock.Client
FROM Stock
LEFT JOIN InitClient C1 ON Client = 1
LEFT JOIN InitClient C2 ON Client = 2
WHERE
(
(Stock.Client = 1 AND Stock.PostingDate > C1.InitDate) OR
(Stock.Client = 2 AND Stock.PostingDate > C2.InitDate)
)
有時擺脫子選擇的簡單步驟就可以解決問題
索引
您可能希望通過創建索引來加速您的程序,例如在Stock.PostingDate.
助手表
您可以創建一個幫助表來存盤Stock記錄的相關資料,因此您可以在一段時間內執行一次慢速查詢,可能一周一次,或者每次新客戶進入階段并將結果存盤在幫助表中。完成先決條件計算后,您將只能查詢包含少量記錄的輔助表,從而達到閃電般的快速行為。因此,我們的想法是很少執行慢查詢,快取/存盤結果并重用它們而不是每次都計算它。
一個新的專欄
您可以在Stock表中創建一個名為的列,InitDate并定期用每條記錄的資料填充該列。第一次執行需要很長時間,但隨后您將只能查詢Stock沒有連接和子選擇的表。
uj5u.com熱心網友回復:
您可以優化此查詢很多。
- 首先,這兩個
LEFT JOINs 基本上只是半連接,因為您實際上并沒有從它們回傳任何結果。所以我們可以把它們變成一個單一的EXISTS. - 您還將獲得到 的隱式轉換
int,因為Clientisvarchar和1,2is anint。因此,將其更改為'1','2',或者您可以更改列型別。 PostingDate也是varchar,那真的應該是date
SELECT
s.Material
,s.Stock
,s.PostingDate
,s.Client
FROM Stock s
WHERE s.Client IN ('1','2')
AND EXISTS (SELECT 1
FROM InitClient c
WHERE s.PostingDate > c.InitDate
AND c.Client = s.Client
);
- 接下來您要查看索引。對于此查詢(不考慮正在運行的任何其他查詢),您可能需要以下索引(洗掉
INCLUDE聚集索引的 )
InitClient (Client, InitDate)
Stock (Client) INCLUDE (PostingDate, Material, Stock)
- 即使使用這些索引,您也有可能對其進行掃描
Stock,因為IN功能類似于OR. 這并不總是發生,值得檢查。如果是這樣,您可以改寫它以使用UNION ALL
SELECT
s.Material
,s.Stock
,s.PostingDate
,s.Client
FROM (
SELECT *
FROM Stock s
WHERE s.Client = '1'
UNION ALL
SELECT *
FROM Stock s
WHERE s.Client = '2'
) s
WHERE EXISTS (SELECT 1
FROM InitClient c
WHERE s.PostingDate > c.InitDate
AND c.Client = s.Client
);
資料庫<>小提琴
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/323666.html
標籤:sql-server sql-server-2012 查询优化
上一篇:如何從多個表中無重復地獲取資料
