2017-09-03 79 views
0

我想查詢一個相當大的表(數百萬行),提供一個種子值,以保證隨機順序的方式 - 但只要使用相同的種子,在多個查詢中保持穩定。SQL Server中的高性能穩定隨機排序?

我來了這麼遠,最好是

SELECT TOP n * 
     FROM tbl t 
    ORDER BY t.int_column % seed, t.int_column 

這是一個有用的方法,無論是從性能的角度和結果行了不同的種子有點均勻分佈?

編輯:

對於上下文,是因爲多個所需要的穩定的排序 - 可能是嵌套 - WHERE NOT IN的查詢對相同的數據集進行操作;例如

SELECT * 
    FROM tbl t 
WHERE t.some_criteria = 'some_value' 
    AND t.id NOT IN 
(
    SELECT TOP n t.id 
      FROM tbl t 
     WHERE t.some_other_criteria = 'some_other_value' 
     ORDER BY t.int_column % seed, t.int_column 
) 
    AND t.id NOT IN 
(
    # etc. 
) 

當子選擇的順序是隨機的,但不是穩定的(即NEWID()TABLESAMPLE()),其結果列大起大落執行之間。

+0

數據在哪裏被消費?如果不是將數據傳遞給另一個存儲過程或其他數據庫內代碼,那麼按照非平凡標準對行進行排序是一種視圖級別的問題,不應該存在於數據庫代碼中,而應該放在應用程序中碼。 – Dai

+0

@戴 - 偉大的問題。請參閱我的編輯。 – vzwick

+0

你總是會對所有記錄進行排序,這些記錄可能相當多。你確定你需要所有'NOT IN'子句嗎?也許你可以稍微簡化查詢。你究竟想達到什麼目的? –

回答

1

如果您想要隨機排序,您可以使用HASHBYTES和您選擇的行中的某些數據執行此操作。現在

SELECT TOP 100 * 
    FROM tbl t 
    ORDER BY HASHBYTES('SHA1', CONCAT(STR(t.int_column), 'seed string')) 

,在此性能是一個大問題。現代CPU非常快速地執行SHA1,所以這可能足夠滿足您的需求。

如果你能詳細瞭解有關性能和更少的「好隨機性,」你可以在一個簡單的linear congruential generator作爲轉換功能下降:

SET ARITHABORT OFF; 
SET ARITHIGNORE ON; 
SET ANSI_WARNINGS OFF; 

SELECT TOP 100 * 
    FROM tbl t 
    ORDER BY ((t.int_column + seed_number) * 1103515245 + 12345) 

這會更快,但隨機的。

+0

與'modulo'相比,'HASHBYTES()'路線不幸的性能明顯降低了90%。我無法完全測試線性同餘發生器性能,因爲它會導致int溢出。 – vzwick

+0

沒關係int溢出('CAST AS bigint'幫助),但*少隨機*有點輕描淡寫;確實,順序是_very_穩定;) – vzwick

+1

LC的「隨機性」來自整數環繞模數的情況(通常這發生在您使用的任何整數類型的最大值處)。我實際上並不知道如何讓SQL Server包裝數學。 –

0

只是一個想法...你可以添加一個「RamdomSort」列給你的表。這樣,排序順序將是真正的隨機數,但會保持可重複的可重複性,直到用新值更新表爲止。沿着這些線...

ALTER TABLE dbo.MyTable ADD RandomSort INT NOT NULL 
CONSTRAINT df_MyTable_RandomSort DEFAULT(0); 


UPDATE mt SET 
    mt.RandomSort = ABS(CHECKSUM(NEWID())) % 100000 + 1 
FROM 
    dbo.MyTable mt; 

SELECT 
    * 
FROM 
    dbo.MyTable mt 
ORDER BY 
    mt.SomeValue; 

如果情況允許它,你甚至可以添加一個覆蓋,非聚集索引來消除排序操作。