在資料倉儲建模時,應該使用哪種資料型別的度量值

深藍發表於2013-11-15

在資料倉儲建模中,很重要的模型就是星型模型,在星型模型中我們將表分為維度表和事實表,事實表中存放的可以進行計算(彙總,平均等)的列就是度量值。要進行計算的度量值,可以選擇的資料型別也有好多種,那麼我們應該選擇哪一種呢?

首先定個大的方向,是整數還是小數?如果是整數,那麼我們可以選擇的資料型別就只有int和bigint了,16位或者8位的整數基本不用考慮,在資料倉儲這種大資料量的環境下,很容易就overflow了。即使是int這種32位的整數,在資料量特別大的情況下,如果要做sum甚至是avg操作,很可能就會溢位,所以一般推薦使用bigint。

對於價格,金額這種型別的資料,一般會記錄成小數,而且是兩位小數,那麼我們使用什麼資料型別來進行儲存呢?以SQL Server為例,我們可以選擇的資料型別包括:

  • float
  • money
  • decimal/numeric

1.Float是一個非精確的資料型別,也就是說,儲存的資料在讀取出來時可能會有一定的誤差。在財務這種一分錢都不能差的系統裡面,是絕對不能採用的資料型別,在資料倉儲中進行sum的話會使得sum的結果與實際結果不一致。但是Float並不是一無是處,筆者使用兩千萬行的資料對幾種小數型別的資料進行效能測試,發現float在進行運算時具有一點優勢,另外Float由於內部是採用科學計數法實現,所以可以儲存非常非常大的數值。

print convert(money,'12345678901234567890');--Error
print convert(decimal,'12345678901234567890');--Error
print convert(float,'12345678901234567890');--Correct

2.Money是SQL Server特有的資料型別,在Oracle,MySQL中沒有對應的型別。money的精度是可以到小數點後4位,所以對於我們平時記錄兩位小數的金額來說,是滿足要求的。如果我們的度量值不是金額,而是其他含義的值,而且精度也不會超過4位小數(比如面積、長度、重量等),那麼還是否可以使用money型別呢?如果只是進行sum、avg這樣的運算,是完全可以使用money型別的。關於money和decimal的效能,有人專門做了個比較,我也使用兩千萬的資料進行了sum和avg的比較,發現money在計算上有一定的效能優勢,但是這個優勢也不是明顯到速度能夠提高好幾倍的程度。老外做的比較的部落格:http://sqlblog.com/blogs/aaron_bertrand/archive/2008/04/27/performance-storage-comparisons-money-vs-decimal.aspx

money型別在進行除法運算的時候,如果沒有轉換為decimal型別,那麼就會造成精度丟失,因為money始終保留4位小數,所以最終結果可能會比decimal型別的有誤差。所以最好不要把money型別的資料參與除法運算。

select sum(money1/money2) from testMoney;

如果一定要參與除法運算,那麼我們可以將一個money型別和一個decimal型別進行除法運算,這樣系統會自動轉換成decimal型別,從而避免由於money只保留4位小數造成的精度丟失。

select sum(money1/decimal1) from testMoney;

3.Decimal型別和money型別一樣都是精確數值型別,不同之處在於decimal型別可以指定佔用的長度和小數後的精度。Decimal可以提供比Money更大的資料範圍和更高的精度,當然也會佔用更多的儲存空間。

如果對於只保留2位小數的度量值,我們可以使用decimal(xx,2)來儲存,前面的值根據資料量和資料值的大小來取,我一般寫成decimal(18,2)。使用decimal型別進行除法運算時,不會出現money型別遇到的小數精度丟失的問題,即使我們只申明瞭decimal(xx,2),但是在進行除法運算的過程中,系統會保留很高的小數精度來進行計算。

Decimal的運算效能不如money,但是差距也不是那麼的明顯,在無法預期的對度量值的運算的情況下,使用decimal更保險。

總結:

如果是整數,就用bigint,避免資料量太大造成的int資料溢位。

如果是小數,而且不是那麼關心精度,可以使用float,如果要計算的數值非法非常大就必須使用float,但是對於一分錢都不能差的情況下,就不要使用float型別。而應該使用money或者decimal。

如果不會有除法運算,而且資料的精度是在小數點後4位以內,那麼使用money,其速度比decimal更快。

如果無法預期會不會有除法運算,或者要求的小數位數精度很高,那麼就得使用decimal,速度比money慢一些,但是基本上還在同一個數量級。

相關文章