SQL Database の V12 で入った Row-Level Security (Azure SQL Database) をちょっと触ってみました。
Row-Level Security の日本語解説はこちらをどうぞ。
SQL Database の Row-Level Security について at SE の雑記
テーブルやユーザー、セキュリティ述語関数 は上記リンクのサンプルのままですが、データを少し増やして試してみました。
まず 非クラスター化インデックスを貼ってみました。
create index IX_Sales_Product on Sales (Product)
これでインデックスを貼った列のみ、条件と取得列に指定したクエリを動かします。
EXECUTE AS USER = 'Sales1'; SELECT Product FROM Sales WHERE Product = 'Valve'; REVERT; EXECUTE AS USER = 'Sales2'; SELECT Product FROM Sales WHERE Product = 'Valve'; REVERT; EXECUTE AS USER = 'Manager'; SELECT Product FROM Sales WHERE Product = 'Valve'; REVERT;
予想通りインデックスが効きませんでした。
理由は、セキュリティ述語関数の中で SalesRep 列を参照しているので、結局 Table Scan になってます。
ではインデックスを変えてみます。
drop index IX_Sales_Product on Sales create index IX_Sales_SalesRep_Product on Sales (SalesRep, Product)
これで同じクエリの結果がこちら
Index Scan で多少マシになってますがまだまだです。
今回のケースだとこれが正解のようです。
drop index IX_Sales_SalesRep_Product on Sales create index IX_Sales_Product_SalesRep on Sales (Product, SalesRep)
というわけで、Row-Level Security の Filter は Index 効いた後に Filter しています。
おまけ
クラスター化列ストアインデックスでも試してみました。
drop index IX_Sales_Product_SalesRep on Sales create clustered columnstore index CCI_Sales ON Sales;
あまり面白い結果じゃないですねー。
というわけで、非クラスター化列ストアインデックスも試してみました。
drop index CCI_Sales on Sales create nonclustered columnstore index NCCI_Sales_SalesRep_Product ON Sales (SalesRep, Product)
列ストアインデックスの場合は、列の順番を入れ替えても変わりなさそうな感じ。
drop index NCCI_Sales_SalesRep_Product on Sales create nonclustered columnstore index NCCI_Sales_Product_SalesRep ON Sales (Product, SalesRep)
インデックスの列を Product だけにすると、インデックスは使われずに Table Scan になりました。
drop index NCCI_Sales_Product_SalesRep on Sales create nonclustered columnstore index NCCI_Sales_Product ON Sales (Product)
まあ普通な感じですね。
Row-Level Security を使うテーブルで普通のインデックスを使う場合は、セキュリティ述語関数の存在も意識しておく必要がありそうでした。