テーブルに追加された計算列はどのように格納されるのか?という話


計算列はとても便利な機能だから使わない選択はない。経験上であったり勉強したりしてすでに知ってはいたことなのだけど、どのように格納されるのか試ししてみよう。ついでに計算テーブルも。SQL Server Analysis Service (Tabular)じゃなくて、Power BI だったらどうなっているのかな?という内容ではある。

計算列であっても通常のテーブルの列同様エンコードされる。でも、計算列って圧縮低くね?って話です。

そもそも

ストレージ モード が Import / Dual であるとき、

  • Table
    • Partition
      • Segment

という構造になっていて データは Segment に格納されている。で、メモリの消費をできるだけ小さくできるよう整理(Encode / Sort) される。集計や計算に利用されるデータのフットプリントが小さければ一度に読み込めるデータ量が増えるはずだから、パフォーマンス向上に期待ができるわけ。

どうなるか見てみる

計算列(Calculated column) だけじゃなく、同時に 計算テーブル(Caluclated table) も。

  • 1 から 130 までの整数値 と それらに対応する 偶数であるか否かの論理値の列
  • 130 行のテーブルを 3つ 用意して比較した。"130" というのはこのケースで見つけた値

データロード前に用意

PowerQuery
let
    Source = Table.FromColumns(
        { { 1 .. 130 } },
        type table [ Column1 = Int64.Type ]
    ),
    AddedCustom = Table.AddColumn(
        Source,
        "Column2",
        each Number.IsEven( [Column1] ),
        Logical.Type
    )
in
    AddedCustom

計算列の追加で

DAX
Table1 = GENERATESERIES( 1, 130, 1 ) 
DAX
CalculatedColumn = ISEVEN( [Value] ) 

計算テーブルで

DAX
Table2 = 
ADDCOLUMNS(
    GENERATESERIES( 1, 130, 1 ),
    "AddColumnCalculatedTable", ISEVEN( [Value] )
)

結果など

DAX Studio の Vertipaq Analyzer 機能で違いを観察する。

Encoding / Dictionary / Hier Size は変化ないのでそれ以外を。

Table Col Size Data
計算列(Table1) 2,384 1,464 24
あらかじめ用意した列 2,368 1,448 8

行数 130 は極小なので差は小さいけど、行数増えることや計算列で得られる値によって差が大きくなる可能性はあるでしょう。

なぜ?

行のソート

考えられる要因としては xVerocity Engine による行のソートでしょう。これは Power BI desktop の テーブル ビュー でみると想像できる。行がソートされているのではないかというのが観察できた。このケースでは 130 行。

データをロードするとき、列ごとの整理(Encode) に加え、どのように行の整理(Sort)するとよいのかな🙄と考慮されているのです。

Column1 は 1 から 130 の連続した整数値。もろもろ考慮され VALUE encoding が選択されていた。VALUE encoding はできるだけ少ない bit 数になるよう変換されたデータ(整数値)を格納する仕組みなのだけど、連続した整数値(高いカーディナリティ)なので Run Length Encoding の適用はスキップ。値の順番に依存する Encoding の効果がないから。
一方、Column2 は 論理値のみ。カーディナリティが低いし量もそこそこあったので、HASH encoding (Dictionary encoding)が選択された。
低いカーディナリティ(TRUE / FALSE しかない)からRun Length Encoding の効果は高いと推測され、テーブル全体で適用されるソートのうち優先順位の高いソート条件に利用されたということでしょう。

計算テーブルでも

最適化された行のソートが適用されているように見える。Vertipaq Analyzer での結果も同じだし同様に扱われたということが予想できている。

計算列では?

同じ集計結果をえられるテーブルではあるけれども 行のソートがされていないように見える。

計算テーブル / 計算列 が用意されるプロセスは、その性質上、通常のテーブルすべての用意が終わってからになる。実際にはもっと複雑なプロセスを経ているけれども、計算列のテーブルへの追加はテーブル行のソートは適用済み。計算列の結果をどのような行のソートにするかの考慮に含めることができない。なので、結果的に圧縮率が低い傾向にあるということ。"計算列 = 圧縮率が低い" ではない。

思ったこと🙄

計算列は便利なので、効果的に使いたいものである。

その他