我有一個包含實時股票報價的SQL Server數據庫。如何從數據庫中刪除幾乎相同記錄的連續序列
有包含你會expect--一個序列號,股票代碼,時間,價格,出價,出價大小,問,問大小等
該序列號對應於消息的行情表接收到的數據包含正在跟蹤的一組股票代碼的數據。每當有任何被跟蹤的符號發生變化時,就會收到一條新消息(帶有一個新的遞增順序號)。該消息包含所有符號的數據(即使沒有任何變化的數據)。
將數據放入數據庫時,每條消息中的每個符號都會插入一條記錄,即使對於自先前消息以來沒有任何變化的符號也是如此。所以很多記錄包含冗餘信息(只有序號改變),我想刪除這些冗餘記錄。
這與除去整個數據庫中除一條記錄以外的所有相同列的組合(已經回答)不同。相反,我想將每個相同記錄的連續塊(除了序列號以外相同)壓縮到單個記錄中。完成後,可能會有重複的記錄,但它們之間的記錄不同。
我的方法是找到連續的記錄範圍(對於股票代碼),其中除了序列號之外的所有內容都是相同的。
在下面的示例數據中,我通過僅顯示序列,符號和價格來簡化事情。複合主鍵爲序列+符號(每個符號在消息中只出現一次)。我想刪除價格與先前記錄相同的記錄(對於給定的股票代碼)。對於股票X這意味着我想刪除的範圍[1,6],以及用於股票YI要刪除的範圍[1,2],[4,5]和[7,7]:
之前:
Sequence Symbol Price
0 X $10
0 Y $ 5
1 X $10
1 Y $ 5
2 X $10
2 Y $ 5
3 X $10
3 Y $ 6
4 X $10
4 Y $ 6
5 X $10
5 Y $ 6
6 X $10
6 Y $ 5
7 X $11
7 Y $ 5
後:
Sequence Symbol Price
0 X $10
0 Y $ 5
3 Y $ 6
6 Y $ 5
7 X $11
需要注意的是(Y,$ 5)出現兩次,但之間(Y,$ 6)。
以下生成我需要的範圍。左外連接確保我選擇第一組記錄(沒有先前記錄不同),而BETWEEN旨在減少需要搜索的記錄數以查找下一個較早的不同記錄(沒有BETWEEN的結果是一樣的,但速度較慢)。我只需要添加一些東西,如「DELETE FROM QUotes WHERE Sequence BETWEEN StartOfRange AND EndOfRange」。
SELECT
GroupsOfIdenticalRecords.Symbol,
MIN(GroupsOfIdenticalRecords.Sequence)+1 AS StartOfRange,
MAX(GroupsOfIdenticalRecords.Sequence) AS EndOfRange
FROM
(
SELECT
Q1.Symbol,
Q1.Sequence,
MAX(Q2.Sequence) AS ClosestEarlierDifferentRecord
FROM
Quotes AS Q1
LEFT OUTER JOIN
Quotes AS Q2
ON
Q2.Sequence BETWEEN Q1.Sequence-100 AND Q1.Sequence-1
AND Q2.Symbol=Q1.Symbol
AND Q2.Price<>Q1.Price
GROUP BY
Q1.Sequence,
Q1.Symbol
) AS GroupsOfIdenticalRecords
GROUP BY
GroupsOfIdenticalRecords.Symbol,
GroupsOfIdenticalRecords.ClosestEarlierDifferentRecord
問題是,這太慢了,並且用於數據庫中的2百萬記錄的內存不足(崩潰SSMS-)。即使我將「-100」更改爲「-2」,它仍然很慢並且內存不足。我期望LEFT OUTER JOIN的「ON」子句限制處理和內存使用(200萬次迭代,每個處理大約100條記錄,這些記錄應該是可處理的),但是似乎SQL Server可能首先會生成所有的根據ON子句中指定的標準選擇表格之前的兩個實例Q1和Q2(約4個12個組合)。
如果我在較小的數據子集上運行查詢(例如,通過使用「(SELECT TOP 100000 FROM引用)AS Q1」,以及類似的Q2),它會在合理的時間內完成。我試圖弄清楚如何使用「WHERE Sequence BETWEEN 0 AND 99999」自動運行20次左右,然後「...... BETWEEN 100000 AND 199999」等(實際上我會使用重疊範圍,如[0, 99999],[99900,199999]等刪除跨越邊界的範圍)。
以下生成一組範圍,將數據拆分爲100000個記錄塊([0,99999],[100000,199999]等)。但是,如何重複應用上述查詢(每個範圍一次)?我一直陷入困境,因爲您無法使用「BETWEEN」對這些進行分組而不應用聚合函數。因此,我不知道如何選擇記錄塊,只知道如何得到不符合上述查詢(如Q1和Q2)的MIN(),MAX()等(單個值)。有沒有辦法做到這一點?這個問題有沒有完全不同的(更好的)方法?
SELECT
CONVERT(INTEGER, Sequence/100000)*100000 AS BlockStart,
MIN(((1+CONVERT(INTEGER, Sequence/100000))*100000)-1) AS BlockEnd
FROM
Quotes
GROUP BY
CONVERT(INTEGER, Sequence/100000)*100000