Sql-Server

在 ado.net 與 SSMS 中執行的查詢產生截然不同的結果

  • January 11, 2021

頂級:我正在執行這個查詢。它已經按照我的預期執行了幾個星期,但是在過去的幾天裡,當我通過 ADO.Net 執行查詢時,我得到了相當隨機的不正確結果,但是當我在中執行完全相同的查詢時仍然得到“正確”的結果SSMS,我不知道為什麼。

我正在編寫一個從 Edgar 網站獲取 SEC 文件的流程。每天晚上,SEC 都會發布一個小型文本文件,其中包含在給定日期完成的文件的“輕量級元數據”(其所在公司的 ID、文件的類型、文件的 ID 號)。您可以快速瀏覽這些內容並大致了解正在發生的事情。這是我編寫的項目的第一階段,我可以通過這種方式在大約一個小時內載入 27 年左右的文件來獲取輕量級元數據。

真正耗時的事情是獲取整個文件並對其進行解析。隨著項目的這一方面的發展,我每天都想獲取新數據,然後獲取並處理一些額外的完整文件,以回填我從輕元數據中知道的文件。

該流程必須適應的另一件事是,公司可以在周一送出文件,並在周五、下週或明年上傳新版本。因此,我必須認識到我何時獲得了對我之前處理過的文件的更新。

換句話說,人們關心最近的東西,所以我想保持最新並在時間允許的情況下填補舊的東西。

所以我有以下查詢,用高級術語來說,詢問“給我前 X 個文件,a)我之前沒有完全處理過,或者 b)得到並更新,我需要重新處理它”

FilingIndex 是從 SEC 發布的有關日常活動的每晚文件中獲取輕量級元數據的表

FilingCiks(Cik 是一個政府公司 id)是一個關於文件引用的公司的一對多表(至少需要這些 id 中的一個來獲取全文以進行處理

FilingContent 是我的表格,我在其中保存我為文件提取和解析的全文中的資訊。

所以每天晚上我都會執行這個過程並獲取今天的“新功能”列表;進入 FilingIndex 和 FilingCiks。

然後我執行這個查詢,說“按照我聽說過的最新文件的順序,給我我需要打電話給美國證券交易委員會的全文”。@max 是我在上一步中找到的文件數量 + 一些幫助回填的文件數量。

我希望看到我剛剛從上一步中獲得的所有文件的列表,然後是我最後一次回填的條目。所以前 5000 行是今天/昨晚的文件,接下來的 5000 行可能會在 2018 年我離開的某個地方出現。

我以這種方式處理了幾年的申請,結果每次都符合我的預期。但是昨天我無緣無故地找到,下面的查詢在通過 ADO.Net 執行時開始返回散點圖結果,但仍然返回我在 SSMS 中所期望的結果。

通過 ADO.Net,結果仍然是逆時針,但是 a)它們不是從最新的開始,並且 b)它們輕輕地跳過現有的行。

有什麼想法為什麼 a) ADO.Net 和 SSMS 會以如此不同的方式執行,b) 為什麼 ADO.Net 執行會在最後一天左右開始表現不同?

正如我所說,我已經執行這個過程一段時間了。我已經返回並填寫到 2018 年 8 月,並且查詢正在按我的預期執行。但現在它在日曆上跳來跳去。

DECLARE @max int = 5000;
SELECT TOP (@max) idx.accession_number, ciks.cik, cast(case when idx.fetched < idx.crawlerdate then 1 ELSE 0 END as bit) as cleanup, idx.CrawlerDate
FROM
(SELECT idx.accession_number, idx.crawlerdate, idx.filingType, ROW_NUMBER() OVER (PARTITION BY idx.accession_number ORDER BY idx.crawlerdate DESC) AS rn, content.fetched
 FROM raw.FilingIndex idx
 LEFT JOIN raw.FilingContent content ON content.accession_number = idx.accession_number
 WHERE idx.accession_number < 999999999700000000 -- paper filings with no good data to mine
      AND (content.accession_number is null OR content.Fetched < idx.crawlerdate)
) idx
CROSS APPLY (SELECT TOP 1 cik from raw.filingciks ciks WHERE ciks.accession_number idx.accession_number AND ciks.crawlerdate = idx.crawlerdate) ciks
WHERE idx.rn = 1
ORDER BY idx.crawlerdate DESC, idx.Accession_Number asc

對於每個欄位中的每個值,您的idx.crawlerdate欄位值是否都是唯一PARTITIONidx.accession_number

換句話說,如果您有兩個crawlerdate相同的值,PARTITION那麼在為您的欄位生成值時,ROW_NUMBER()將隨機選擇哪條記錄在平局中獲勝。rn(這是由於在非唯一欄位上排序數據集的不確定性。)

要解決此問題,您需要添加另一個欄位來統一函式ORDER BY子句的邏輯,或者您可以使用或生成行號。如果您使用or然後在同一行中具有相同的行將被分配相同的排名編號。ROW_NUMBER()``RANK()``DENSE_RANK()``RANK()``DENSE_RANK()``crawlerdate``PARTITION

ROW_NUMBER()是關於使用該函式時可能發生的非確定性排序的好讀物。

另外,我同意@JustinCave 的觀點,即您的ciks查詢SELECT TOP 1 cik from raw.filingciks ciks WHERE ciks.accession_number idx.accession_number AND ciks.crawlerdate = idx.crawlerdate是不確定的,因為您使用的是TOP沒有運算符的ORDER BY運算符。根據您的數據,您還可以在那裡獲得隨機結果。

好吧,現在我覺得自己很愚蠢…

我在 C# 中添加了一些程式碼以獲取 ADO.Net 查詢計劃,並拉動該執行緒將其一直帶回到我對如何處理命令行參數所做的一些更改。

結果如此不同的原因是因為它沒有執行我認為的那樣,並且創建查詢的 C# 中的一個動態變數具有意外的值。

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