DocumentDB で TOP によるページングをサポート、クエリ機能を強化

このポストは、12 月 15 日に投稿された DocumentDB paging support with TOP and more query improvements の翻訳です。

このたび Azure DocumentDB に対するクエリの実行方法について多くの改善がなされました。今回のサービス更新では、SQL 構文への TOP キーワードの導入、クエリの実行速度向上とリソース消費低減、クエリ演算子の制限引き上げ、.NET SDK での LINQ 演算子のさらなるサポート追加が実施されています。

今回の変更点は以下のとおりです。

  • 新しい SQL キーワード: クエリ結果のページングと制限を行う TOP キーワードが導入されました。
  • 制限の引き上げ: OR を最大 20 個、また IN 式でアイテムを最大 200 個まで使用できるようになりました。
  • パフォーマンスの改善: クエリ エンジンが改良され、フィルターが適用された並べ替えクエリの実行速度の向上、インデックス計画のさらなる最適化、大規模な結果セットでのクエリの差分処理の改善がなされました。
  • 新しい LINQ 演算子: Take()、CompareTo()、条件演算子、合体演算子など、多数の LINQ 演算子が新たにサポートされるようになりました。

この記事では、今回の更新内容について説明しながら、Azure DocumentDB を使用して高速でスケーラブルなアプリケーションを構築する際にどのように活用できるかを見ていきます。

 

TOP でクエリ結果のページングと制限が可能に

DocumentDB の SQL 構文に TOP キーワードが導入されました。TOP は DocumentDB に対する SQL クエリ内で使用でき、クエリ結果をページ単位に分割したり、クエリが返す結果の数を制限したりできます。

 SELECT TOP 100 *
FROM food
WHERE food.foodGroup = "Snacks"
ORDER BY food.description

TOP は有効な DocumentDB のクエリであればあらゆるクエリで使用可能です。パラメーター化されたクエリではアイテム数をパラメーターで指定することもできます。また、TOP を ORDER BY と組み合わせて使用すると、MIN、MAX、FIRST の各セマンティクスを DocumentDB のクエリに実装できます。

詳細については、DocumentDB のクエリに関するドキュメントを参照してください。

SQL 演算子の上限が拡大

先日は、DocumentDB のクエリでサポートされている AND、JOIN、UDF の各演算子の数の制限引き上げが発表されました。フレームワーク開発者の皆様からは、柔軟なクエリ API を構築するためにクエリ 1 つあたりの OR 演算子や IN 演算子の制限も引き上げてほしいというご要望を多数いただきました。これを受けて、下記の制限引き上げを行いました。

  • クエリ 1 つあたりの OR 句の数が最大 20 に
  • クエリ 1 つあたりの IN 式内で指定できる値の数が最大 200 に

この変更により、LINQ で IN またはこれと同等の IEnumerable.Contains (機械翻訳) 演算子を使用して、従来よりも大規模な範囲でデータを取得できるようになりました。また、DocumentDB へのラウンドトリップ数も低減されています。

 /* クエリ 1 つあたり 200 個まで値を指定可能 */
SELECT *
FROM food
WHERE food.id IN (
    "0326", "0327", "0329", "03230"
) 

DocumentDB の制限の詳細は、こちらのドキュメント (英語) でご確認ください。

SQL クエリ エンジンのパフォーマンスが向上

DocumentDB のクエリ エンジンに対しても多くのパフォーマンス強化が行われ、クエリの要求単位 (RU) 消費の削減、レイテンシの短縮、長時間におよぶクエリを実行する際に必要となるラウンドトリップ数の抑制が実現されました。

フィルターが適用された並べ替えクエリの実行速度の向上

並べ替えとフィルタリングを行う式全体で、論理的なクエリ実行プランが最適化されるようになりました。たとえば、同一のプロパティに対してフィルタリングと並べ替えを行うクエリでは、実行速度が桁違いに向上し、ラウンドトリップ数も大幅に減少します。

  • DocumentDB で Azure Search コネクタを使用する場合、この最適化によってインデクサーが消費する要求単位が大幅に減少し、また実行速度も向上します。
  • 一般的な例としては、下記のようにフィルターで範囲指定したうえに並べ替えて読み込む場合、クエリが消費する要求単位が減少し、実行速度が向上します。
 /* 実行速度が桁違いに向上 */
SELECT * 
FROM deviceTelemetry 
WHERE deviceTelemetry._ts > @highWaterMark
ORDER BY deviceTelemetry._ts

パフォーマンスに関するヒント: 範囲を指定するフィルターを使用している (タイムスタンプの値を使用する) クエリでは、同一のプロパティに対して ORDER BY 句を追加することでこの最適化の効果が得られます。

インデックス計画のさらなる最適化

DocumentDB のクエリ実行エンジンで、式の並べ替えや、負荷が大きいフィルターを実行するか否かのトレードオフの評価などが行われることにより、クエリのフィルター式の分析や実行パフォーマンスの最適化が改良されました。この変更により、さまざまなクエリの実行速度が向上し、また要求単位の消費が削減されます。

 /* このクエリでは DocumentDB によって式が並べ替えられ、パフォーマンスが向上 */
SELECT *
FROM loggedMetrics l
WHERE l._ts > @highWaterMark 
​AND l.traceLevel = 'Critical'
AND l.appName = 'BackendWorkerRole'

 

差分処理の改善

DocumentDB では、実行時間が長いクエリを継続トークンによりサポートしています。各クエリには DocumentDB から一定の時間とリソースが割り当てられ、これに達すると継続トークンが返され、それが実行再開時にブックマークとしての役割を果たします。

DocumentDB は、クエリの詳細な状態をサーバー側で保持しません。クエリの状態はすべてトークン自体に含まれているため、期限が切れることはなく、またクライアントにキャッシュすることが可能です。このため、マイクロソフトでは大規模な結果セットを扱うクエリの継続中の状態をコード化する方法を大幅に改善しました。

 /* ドキュメントをスキャンしてクライアント側で COUNT を構築するクエリ */
SELECT VALUE 1
FROM loggedMetrics
WHERE loggedMetrics.startTime >= "2015-12-12T10:00:00Z”

上記のようなクエリを実行する場合、要求単位の消費数と実行時間が 1/2 ~ 1/3 になります。

新しい LINQ 演算子

最新版の DocumentDB .NET SDK リリース 1.5.2 (英語) では、ページング、条件式、範囲比較に対応した新しい演算子が追加されるなど、LINQ クエリ変換のサポートが拡張されました。この変更により、SQL 文字列を構築しなくても DocumentDB を動的に操作できるシナリオが広がり、それに対応するスムーズな LINQ 式を作成できるようになりました。サポートされる LINQ 演算子の詳細については、LINQ に関するのドキュメントに記載されています。

DocumentDB では、Take 演算子を使用してクエリ結果の数を制限できます。

 client.CreateDocumentQuery<Family>("/dbs/sampleData/colls/families")
    .Where(f => f.LastName == "Andersen")
    .OrderByDescending(f => f.Address.State)
    .Take(10);

また、DocumentDB ではリレーショナル SQL のように文字列の範囲を比較 (英語) できますが、CompareTo 演算子を使用すれば、これを LINQ で実現できます。下記のクエリでは、姓が N ~ Z で始まる家族を取得しています。

 client.CreateDocumentQuery<Family>("/dbs/sampleData/colls/families")
    .Where(f => f.LastName.CompareTo("N") >= 0);

SDK ではほかにも、C# の条件演算子 (?)合体演算子 (??) から対応する DocumentDB 演算子への変換がサポートされています。今回の更新により、自動生成された LINQ 式で ODATA などのフレームワークから下位の DocumentDB へのパス スルーを簡単に実行できるようになります。

 client.CreateDocumentQuery<Family>("/dbs/sampleData/colls/families")
    .Select(f => f.LastName?? "Unknown");

次のステップ

DocumentDB に対するクエリを利用するには、サポートされている SDK のいずれかをダウンロードして使用するか、Azure ポータルから実行します。サポートが必要な場合やご質問、ご意見がありましたら、Stack Overflow の開発者フォーラム (英語) までお寄せください。こちら (英語) からは DocumentDB エンジニアリング チームとの個別チャットを予約していただけます。

また、Twitter アカウント (@DocumentDB) をフォローすると、DocumentDB の最新情報や新機能をいち早くチェックしていただけます。