哈希算法在數據庫中的用途


哈希算法在數據庫中的用途

轉載自:http://blog.sina.com.cn/s/blog_624f972301013bau.html

 1 上次提到了使用哈希算法做密碼的單向加密,其實哈希算法的用途還有很多,比如傳輸文件時做校驗,對數據進行簽名等。除了這些,在數據庫里面還有什么地方可以用到哈希算法呢?最重要的一個是哈希查找,由於哈希算法能夠很好的把數據做比較均勻的分布,所以哈希查找的速度要比B+ Tree查找的速度要快。哈希查找的時間復雜度是O(1),而B+ Tree的時間復雜度是O(h)。當然,B+ Tree的優勢是在范圍查找,不然也不會成為關系型數據庫的基本算法了。
 2 SQL Server在做聯接(JOIN)的時候,如果兩個表都不是很小,而且沒有在關聯列上排序,就很可能使用哈希聯接。哈希聯接使用的就是哈希查找,它的性能並不差,但是要注意的一點是,哈希聯接需要先構造一個哈希表,而哈希表需要消耗不小的內存空間,如果數據庫服務器的內存不足的話,SQL Server就只好使用“優雅的哈希聯接”(Grace HASH JOIN)或者遞歸哈希聯接(Recursive Hash Join),這樣性能就會受到影響了。在設計數據庫的時候,我們應該注意建立/更新適當的索引和統計信息(STATISTICS),以便SQL Server可以准確的估計聯接的輸入大小,以便選擇正確的算法。
 3 在使用哈希聯接的時候,SQL Server的查詢優化器會選擇算法,通常我們並不需要做任何的指令,編寫任何代碼。但是在其它一些需要用到哈希算法的時候,就需要認真的選擇算法,甚至可能需要自己寫哈希算法的代碼。
 4 在業務系統中,可能生成的業務鍵(Business key)會比較長,例如某電商網站的訂單號會類似這樣:202210782169AC7G。這樣的業務鍵如果用作主鍵的話,會占據16字節,顯得有點浪費。如果只是單一系統使用,可以考慮用自動增量的數字作為主鍵。但是如果在多個系統中使用,比如在一個數據倉庫系統中,使用自動增量作為代理鍵(Surrogate key),就必須在處理事實表的ETL過程中,用新的自動增量替換掉訂單表和詳單表中的訂單號,這會帶來兩個大表的JOIN,是一個相當耗時的操作。在這種情況下,我們就可以考慮使用哈希算法來生成代理鍵,只需要在訂單表和詳單表都使用同樣的哈希算法,就可以保證得到的代理鍵是可以正確聯接的。
 5 熟悉哈希算法的人都知道,哈希算法是可能產生碰撞(collision)的,簡單的說,就是多個不同的輸入可能得到一個相同的輸出。如果我們使用哈希算法生成代理鍵,就可能會出現錯誤。一種解決方案是用不同的桶(bucket)來存放這些哈希值。不過對於數據倉庫系統來說,可以考慮忽略碰撞。畢竟數據倉庫的主要用途是統計分析,而不是需要精確對賬。
 6 SQL Server內置的哈希算法,MD2、MD4 和 MD5 輸出是 16 個字節,SHA 和 SHA1 輸出是 20 個字節。如果用來做這個用途的話,顯得就得不償失了。我們可以考慮編寫其它的哈希函數,輸出更短,速度也更快,不過要注意的是,輸出越短,碰撞的可能性就越高。
 7 下面介紹一個哈希算法的代碼,這個算法叫FNV1a,(Fowler-Noll-Vo variant "1a"),速度很快,碰撞也較低,適合用來對較短的字符串做哈希。這段代碼里面給出了三個不同長度的結果,分別是16位(2字節,SMALLINT)、32位(4字節,INT),64位(8字節,BIGINT),在實際應用時請根據對碰撞率和性能的需求選用。該代碼C++完全來自www.sqlservercentral.com。
 8          .Net C++代碼
 9 using System;
10 using System.Data;
11 using System.Data.SqlClient;
12 using System.Data.SqlTypes;
13 using Microsoft.SqlServer.Server;
14 using System.Text;
15  
16 public partial class UserDefinedFunctions
17 {
18  
19     static readonly ulong prime64 = 1099511628211;
20     static readonly ulong offset64 = 0xcbf29ce484222325;
21     static readonly uint prime32 = 16777619;
22     static readonly uint offset32 = 2166136261;
23  
24     [SqlFunction(IsDeterministic = true, IsPrecise = true, DataAccess = DataAccessKind.None)]
25     public static SqlInt64 xf_GetHash64(SqlString value)
26     {
27         return (SqlInt64)HashFNV1a_64((string)value);
28     }
29  
30     [SqlFunction(IsDeterministic = true, IsPrecise = true, DataAccess = DataAccessKind.None)]
31     public static SqlInt32 xf_GetHash32(SqlString value)
32     {
33         return (SqlInt32)HashFNV1a_32((string)value);
34     }
35  
36     [SqlFunction(IsDeterministic = true, IsPrecise = true, DataAccess = DataAccessKind.None)]
37     public static SqlInt16 xf_GetHash16(SqlString value)
38     {
39         return (SqlInt16)HashFNV1a_16((string)value);
40     }
41  
42     private static long HashFNV1a_64(string value)
43     {
44         ulong hash = offset64;
45         byte[] bytes = Encoding.UTF8.GetBytes(value.ToLower());
46  
47         for (int i = 0; i < bytes.Length; i++)
48         {
49             hash = (hash ^ bytes[i]) * prime64;
50         }
51         return (long)(hash - long.MaxValue);
52     }
53  
54     private static int HashFNV1a_32(string value)
55     {
56         uint hash = offset32;
57         byte[] bytes = Encoding.UTF8.GetBytes(value.ToLower());
58  
59         for (int i = 0; i < bytes.Length; i++)
60         {
61             hash = (hash ^ bytes[i]) * prime32;
62         }
63         return (int)(hash - int.MaxValue);
64     }
65  
66     private static short HashFNV1a_16(string value)
67     {
68         uint MASK_16 = (((uint)1 << 16) - 1);   
69         uint hash = offset32;
70         byte[] bytes = Encoding.UTF8.GetBytes(value.ToLower());
71  
72         for (int i = 0; i < bytes.Length; i++)
73         {
74             hash = (hash ^ bytes[i]) * prime32;
75         }
76  
77         hash = (hash >> 16) ^ (hash & MASK_16);
78         return (short)(hash - short.MaxValue);
79     }
80 };
81 編譯該代碼為dll后,將其封裝為CLR函數。
82 CREATE ASSEMBLY HashFNV1a FROM 'C:\Documents\Visual Studio 2010\Projects\SQLCLR\SQLCLR\bin\Release\HashFNV1a.dll'; --請修改為你編譯出來的dll完整路徑
83 CREATE FUNCTION dbo.xf_GetHash16 (@str nvarchar(4000)) RETURNS SMALLINT
84 AS EXTERNAL NAME HashFNV1a.UserDefinedFunctions.xf_GetHash16;
85 CREATE FUNCTION dbo.xf_GetHash32 (@str nvarchar(4000)) RETURNS INT
86 AS EXTERNAL NAME HashFNV1a.UserDefinedFunctions.xf_GetHash32;
87 CREATE FUNCTION dbo.xf_GetHash64 (@str nvarchar(4000)) RETURNS BIGINT
88 AS EXTERNAL NAME HashFNV1a.UserDefinedFunctions.xf_GetHash64;
89 GO
90  

 

 

http://www.zhihu.com/question/24421843

數據倉庫中,什么是business key?跟surrogate key, primary key, foreign key 有什么區別聯系?

維度建模理論中,維表里使用原業務中的主鍵作為主鍵就是業務鍵(Business Key 跟業務有關的);建立新的主鍵就是代理鍵(Surrogate Key 一般跟業務無關,跟原來的業務主鍵無關並,所以一般使用自增列作為Surrogate Key)。數據庫理論中主鍵(primary key)是本表中是唯一的、不可為空的標識;外鍵(foreign key)和另一張表的主鍵關聯。




Nvarchar可以設的最大長度是多少?想把Nvarchar(max)作為主鍵存文件地址之類的字符串,但是Nvarchar(max)不可以。有什么辦法可以解決么?
https://social.technet.microsoft.com/Forums/zh-CN/aa7af274-d3a7-4077-969e-15113b33d5a7/nvarcharnvarcharmaxnvarcharmax?forum=sqlserverzhchs

Nvarchar可以設的最大長度是多少?想把Nvarchar(max)做主鍵,用來存儲較長的文件地址信息,但是sql server不可以。有什么辦法可以解決么?難道要用int類型作為主鍵么?我擔心的主要是插入的重復問題,c#程序將數據集合向數據庫的表格插入時會產生不重復的id和重復的地址。

另外如何判斷插入的字符串超過了Nvarchar(max)的最大長度


嗨,

Pkey 最大長度為900byte,一般來說很少會使用那麼長的資料當作Pkey,

或許你可以改用Surrogate Key 試試看,及建立一個唯一值來讓資料庫索引,但不要顯示給使用者看。建立新的主鍵比如用自增列建立一個新的跟業務無關的主鍵叫代理鍵Surrogate Key

---------------------------------------------------------------

比如在一個數據倉庫系統中,使用自動增量作為代理鍵(Surrogate key),就必須在處理事實表的ETL過程中,用新的自動增量替換掉訂單表和詳單表中的訂單號,這會帶來兩個大表的JOIN,是一個相當耗時的操作。在這種情況下,我們就可以考慮使用哈希算法來生成代理鍵,只需要在訂單表和詳單表都使用同樣的哈希算法,就可以保證得到的代理鍵是可以正確聯接的。

 

http://mysql.taobao.org/monthly/2019/11/02/#jump
一個hash join算法實現需要三個步驟:
選擇合適的連接參與表作為內表(build table),構建hash表;
然后使用另外一個表(probe table)的每一條記錄去探測第一步已經構建完成的哈希表尋找符合連接條件的記錄;
輸出匹配后符合需求的記錄;
哈希連接根據內存是否能夠存放的下hash表

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM