RedShiftでDECIMAL(NUMERIC)を使用する際の有効桁数について

こんにちは。データサイエンティスト兼、データ基盤エンジニアのshobyです。

皆さんは、RedShiftで小数点数を扱う際に、どのような型を使用していますか? 今回は、固定精度で小数点数を扱うことのできるDECIMAL(NUMERIC)と、その有効桁数についてご紹介します。

※なお、この記事内では、RedShiftのドキュメントに合わせ、NUMERICではなくDECIMAL表記を使用します。

概要

  • DECIMALとは
  • DECIMALの用途
  • DECIMALで値を格納する際の注意点
  • DECIMALで値を計算する際の注意点
  • TVISION INSIGHTSでの活用事例

DECIMALとは

DECIMALとは、固定精度で小数点数を格納することのできるデータ型です。

最大38桁の精度を持つことができ、定義した精度内では丸め誤差を考慮せずに値を格納することができます。

docs.aws.amazon.com

型の定義方法は以下の通りです。

DECIMAL(precision, scale)

precision

整数部と、少数部を合わせた合計の有効桁数です。 例として、整数1桁、小数点以下2桁*1を有効桁数としたい場合、3を指定します。

最大38まで指定することができます。

scale

少数部の有効桁数です。 小数点以下2桁を有効桁数としたい場合、2を指定します。

最大37まで指定することができます。

DECIMALの用途

DECIMALは、主に3つの用途に活用できます。

お金の計算など小数点以下の誤差が許容できない場合

こちらは、一般的なDECIMALの用途です。 ドルでお金を計算する場合など、小数点以下の値を誤差なく計算したい場合に使用します。

DOUBLE PRECISION以上の有効桁数で小数点数を扱いたい場合

DOUBLE PRECISIONの有効桁数は15桁であるため、 それ以上の精度で小数点数を扱いたい場合にはDECIMALを利用する必要があります。

具体的には、整数部が10桁、少数部が10桁といった、 巨大かつ小数点以下も重要な数を扱う場合、 DOUBLE PRECISIONでは有効桁が足りなくなる場合があります。*2

そのような場合、以下のようにDECIMALを利用する必要があります。

DECIMAL(20, 10)

整数の有効桁数を制限したい場合

格納する整数の有効桁数が決まっている場合、 DECIMALを利用することで、異常値が格納されることを防ぐことができます。

例として、分類を表す2桁のカテゴリコードを格納する場合、 DECIMAL(2, 0)を指定すると、3桁以上の値が入らないように制限できます。

CREATE TABLE data (
  category_code DECIMAL(2, 0)
);

DECIMALで格納する際の注意点

DECIMAL型で値を格納する場合、不必要に長い有効桁数を使用しないように注意する必要があります。 DECIMAL型は有効桁数に合わせて必要なストレージ容量が変わり、 precisionが19以下のDECIMALは64ビット(8バイト)、それ以上の場合は128ビット(16バイト)を利用します。

docs.aws.amazon.com

最大でDOUBLE PRECISION(8バイト)の倍のストレージ容量を使うため、不要に長い有効桁数を使うと、クエリの実行が遅くなる可能性があります。

DECIMALで計算する際の注意点

DECIMALを数値計算に使用した場合、計算結果の有効桁数は元のDECIMALと変わることに注意する必要があります。

多くの場合、元の有効桁数よりも多くの桁数が必要になります。

有効桁数がDECIMALの最大桁数である38桁を突破すると、小数点以下が丸められたり、オーバーフローエラーが発生します。

計算後の桁数は、加減乗除それぞれで異なります。

加算・減算

DECIMAL(p1, s1) + DECIMAL(p2, s2)もしくは、 DECIMAL(p1, s1) - DECIMAL(p2, s2)という加算・減算を行う場合、以下の式でprecisionとscaleが決まります。

scale = max(s1,s2)
precision = max(p1-s1,p2-s2)+1+scale

具体例として、DECIMAL(2, 1) + DECIMAL(1, 0)の場合は、以下のようにDECIMALI(3, 1)が必要になります。

scale = max(1, 0) = 1
precision = max(2-1, 1-0)+1+1 = 3

乗算

DECIMAL(p1, s1) * DECIMAL(p2, s2)という乗算を行う場合、以下の式でprecisionとscaleが決まります。

scale = s1+s2
precision = p1+p2+1

具体例として、DECIMAL(2, 1) + DECIMAL(1, 0)の場合は、以下のようにDECIMALI(3, 1)が必要になります。

scale = 1+0 = 1
precision = 2+1+1 = 4

除算

DECIMAL(p1, s1) / DECIMAL(p2, s2)という除算を行う場合、以下の式でprecisionとscaleが決まります。

scale = max(4,s1+p2-s2+1)
precision = p1-s1+ s2+scale

具体例として、DECIMAL(2, 1) + DECIMAL(1, 0)の場合は、以下のようにDECIMALI(5, 4)が必要になります。

scale = max(4,1+1-0+1) = 4
precision = 2-1+0+4 = 5

TVISION INSIGHTSでの活用事例

TVISION INSIGHTSでは、DBに少数点数を誤差なく格納するためにDECIMALを利用しています。

TVISION INSIGHTSの提供するテレビ視聴質データは、CMの出稿など多額の広告費が動く意思決定に用いられるため、 お金の計算と同様な正確な計算が必要なデータとして考えており、計算に誤差のないように取り扱っています。

まとめ

RedShiftではDECIMALを活用することで、有効桁数内であれば丸め誤差を気にせず値の格納と計算を行うことができます。

DECIMALは、お金の計算など小数点以下の誤差が許容できない場合や、DOUBLE PRECISION以上の有効桁数で小数点数を扱いたい場合、整数の有効桁数を制限したい場合などに活用することができます。

TVISION INSIGHTSではテレビ視聴質データの正確な格納と計算のため、DECIMALを利用しています。

*1:-9.99〜9.99

*2:TVISION INSIGHTSでは、全調査世帯の1秒毎の視聴データ数年分の集計といった巨大な小数点数を扱う必要が出てくるため、十分な精度が必要になります。