SQLはユーザーがデータベースを利用する一般的な方法であり、SQLを通じてデータの定義、格納、更新、クエリなど、すべてのデータ管理操作を実現できます。これは高度に非手続き的なプログラミング言語であり、ユーザーは「何をするか」を指示するだけで、「どのようにするか」を具体的に指定する必要はありません。また、データの格納方法を指定する必要もなく、具体的なデータ格納方式を理解している必要もありません。SQLはむしろ「口語的」なプログラミング言語であり、私たちが普段話す言葉と同じように、主語・述語・目的語の階層構造を持っています。例えば、図書館で本を借りるとき、司書に「中国近代史を一冊ください」と言うように、SQL文は select * from book where book_name='中国近代史' となります。司書は事前にすべての本を分類・整理しておく必要があります。例えば、「中国近代史」という本を入庫するとき、「文史類エリア・近現代史の棚・2段目の3番目の位置」に置くことで、後から本を取り出すときに非常に便利です。逆に、本を入庫するときに適当に積み上げるだけでは、本が少ない間は何とかなるかもしれませんが、本が増えると針の山を探すような効率の悪さに陥ります。 この「分類・整理」という管理方法が、データベースのSCHEMAにおけるインデックス構造です。効率的で合理的なインデックス設計は、SQLパフォーマンスにとって極めて重要です。私たちがよく言うSQL最適化の中核は、SQL実行時のデータスキャン量をどのように削減するか、つまりSQLインデックスの最適化です。日常的にSQLを使用する過程では、単一のSQLを最適化するよりもはるかに複雑なシナリオを考慮する必要があります。例えば:
- 既存のインデックスに対して、どのようにSQLを書けばパフォーマンスが向上するか?
- 単一のSQLに対して、どのようなインデックスを作成すればパフォーマンスが向上するか?
- ある業務システムに対して、どのように合理的なインデックスを設計すれば最高のパフォーマンスを達成できるか?
- あるデータベースで異常が発生した場合、どのように問題のあるSQLを特定し、迅速に復旧するか?
本章では、主に開発段階、統合段階、運用保守段階の各プロセスにおけるSQL最適化体系の構築について紹介します。
開発段階:良いSQLを書く
日常の開発プロセスにおいて、良いSQLを書くためには、最も重要なのは3つのことです:
- SQL開発規範を設定し、厳格に規範に従って実行する。
- 業務シナリオに基づいてスキーマを合理的に計画し、SQLが効率的なインデックスを経由するようにする。
- 單一のSQLに対して、最適化可能なシナリオを検討する。
SQL開発規範は、SQL品質保証の基盤であり、SQLをより安定させるための重要な手段です。SQL実行段階で発見されるSQL問題は、既に業務に影響を及ぼしている可能性があり、一般的なSQL緊急対応ではすべてのSQL問題をカバーできないため、比較的受動的です。そのため、明確なSQL開発規範を策定することで、SQL問題の発生タイミングを開発段階に前倒しし、コード内での低レベルなSQLエラーの解消や潜在的なSQLリスクの回避が可能になります。
スキーマ設計は、業務シナリオが絶えず変化する中で、継続的に設計と最適化を行うプロセスです。複雑な業務システムには多種多様なSQLが含まれており、各SQLの負荷構造は業務モデルの変化に伴って変化します。また、基盤となる業務データの継続的な書き込みも、データ分布の絶え間ない変化を引き起こします。私たちは、SQLの負荷状況に応じてスキーマ設計を継続的に最適化し、SQLが業務スループットに対応する最適な状態を維持する必要があります。結局のところ、すべてのSQLのパフォーマンスを最適化することを目的としているわけではありません。それは不要であり、実現も困難です。なぜなら、それにはより高いコストがかかる可能性があるからです。
単一のSQLに対して最も重要なのは、SQLが合理的なインデックスを経由するようにすることであり、データスキャン行数を削減することが最も効果的なチューニング手法です。さらに、業務の観点から考え、そのSQLが実現する業務要件に対して、より合理的な方法が存在するかどうかも検討する必要があります。同時に、SQLが本番環境に導入された後、データの変化に伴ってパフォーマンスの折れ点や潜在的なリスクが生じる可能性も予測する必要があります。
開発段階で良いSQLを書けば、SQLの安定性を最大限に保証し、根本的に不良SQLの発生を抑えることができます。
統合段階:リスクのブロック
統合段階でSQLを本番運用環境に投入する際、最も重要なのは一つだけです:SQLレビューです。コードを書いた後にテストを行うように、コミット前のコードレビューと同じで、SQLレビューは開発プロセスにおいて欠かせません。では、SQLレビューでは主に何に注目するのでしょうか?
- SQL開発規範のチェック
- SQLパフォーマンスの評価
SQL開発規範のチェックとは、SQLが開発規範に準拠しているかスキャンし、開発規範の徹底を支援することです。SQL開発規範の実施は、低レベルなSQLエラーを減らし、低パフォーマンスなSQLシナリオの発生を防ぐだけでなく、SQLの可読性を高め、業務シナリオの理解を容易にし、人為的なSQL問題のトラブルシューティングを支援することができます。
SQLパフォーマンス評価では、多くのSQLリスクを事前に特定する必要があり、主に効率的なインデックスへの乗り換え、Rewriteによる最適化の必要性、パフォーマンス低下の有無などに注目します。審査時にデータサポートや業務シナリオの理解が必要な場合は、実装方法についてさらに詳細なレビューを行うことができます。
統合段階でSQLのリスクをレビューすることで、問題のあるSQLの本番環境への投入を効果的にブロックし、プロセス全体で不良SQLの発生を削減することができます。
運用保守段階:臨機応変な対応
運用保守段階で行われるSQL最適化は、一般的に最も多く取り扱うケースです。SQLが新たに稼働した当初は、データ量が少なく並行処理の負荷も低いため、多くのSQLではパフォーマンス上の問題が発生しません。しかし、業務量の増加やデータの蓄積に伴い、SQLが徐々に遅くなったり、実行計画の急激な変化によってパフォーマンスが急落したりすることがあります。運用保守段階で必要なSQL最適化には、以下のような事項が含まれます:
- 異常診断:問題のあるSQLを特定する
- 根本原因分析:DBが突然クラッシュさせたSQLを特定する
- SQL緊急対応:根本原因となるSQLに対して緊急対応を行い、DBを復旧する
- 日常的な管理:DB内の劣悪なSQLを継続的に管理する
- 継続的な最適化:異常事例をアーカイブし、類推による改善を図る
異常検出と根本原因分析では、一般的なSQL問題を理解し、SQL異常の調査経験を蓄積・体系化することが求められます。これにより、根本原因を迅速に特定し、緊急対応を行って業務への影響を最小限に抑えることが可能になります。ここでは、一般的なSQLの典型的なシナリオと事例を紹介します。
SQL緊急対応は大まかに二つの方法に分けられます:実行計画の介入とSQLの制限です。SQLに正しい実行計画や適切なインデックスが存在する場合、OceanBaseのアウトラインを使用して計画やインデックスをバインドし、実行計画を介入することで、迅速かつ効果的に復旧できます。インデックスの追加が必要な場合は、復旧に時間がかかり、インデックスの作成が完了してから初めて介入効果が得られます。SQLの問題が計画選択によるものでない場合、多くはSQLの容量に関連する問題であり、効果的な方法はSQLの制限です。ただし、SQLの制限は業務に影響を与えるため、SQLの並行処理を犠牲にして全体のDBを回復する必要があります。
日常的な管理と継続的な最適化では、データベースの運用保守プロセスにおいて、データベース上の低パフォーマンスSQLの最適化を継続的に推進し、劣悪なSQLによるデータベースクラッシュのリスクを低減する必要があります。