「SQL Serverの速度改善を指示されたが、具体的な方法がわからない……」とお困りではありませんか?
改善のポイントとなるクエリやテーブル設計のベストプラクティスは、実務経験を積まないとなかなか身につけられないものです。
そこで本記事では、クエリの内容やテーブル設計を中心に、SQL Serverの速度を改善する代表的な方法を紹介いたします。
SQL Serverの動作が重くてお困りであれば、ぜひ参考にしてください。
目次
SQL Serverの速度を改善する必要性
もしかすると「SQL Serverの速度が多少遅くても、大きな問題にならないのでは?」と考えている担当者様もいらっしゃるかもしれません。
しかし実際には、SQL Serverの速度がシステムやサービスの品質に大きく影響するのです。
スマホのアプリケーションを例に挙げて考えてみましょう。
バックエンドで動いているSQL Serverの速度が遅くなると、当然アプリケーションそのものの動作も遅くなります。
たとえそれが数秒であっても、ユーザーにとっては大きなストレスとなりかねません。
結果として利用者が減少し、自社のビジネスにも多大なるダメージを与えてしまうわけです。
このような事態を避けるためにも、SQL Serverの運用時はパフォーマンス監視を徹底し、処理の高速化に努める必要があります。
速度改善の方法にはさまざまありますが、すぐに実行できるものとしてはクエリのチューニングが最適です。
そこで本記事では以降、クエリチューニングに比重を置いて速度改善の方法を解説していきます。
特定のクエリの速度を改善する際の流れ
パフォーマンスに影響を及ぼしているクエリをチューニングする際は、以下の手順に沿うのが一般的です。
クエリをチューニングする際の手順
- クエリを実行し指標を計測する
- 検索述語(WHERE句に指定しているキー)の選択率を確認する
- クエリを修正し、インデックスを作成する
- 再度指標を計測する
クエリを修正する手順での実際の作業内容は、明らかとなった改善点の内容によって変わります。
想定される改善点とその修正方法は、次項にて詳しく解説しますので引き続きご覧ください。
このほかには、sys.dm_exec_query_statsを使用してチューニングする方法があります。
これは過去に実行されたクエリのパフォーマンス統計を取得するもので、稼働中の本番環境でパフォーマンスの指標を取得する際などに有用です。
システム開発中の性能測定は先に紹介した手順のほうが適しているので、状況に応じて使い分けるのがおすすめです。
SQL Serverの速度を上げる方法
ここからは、SQL Serverの速度改善が見込める、クエリチューニングの具体的な方法を紹介します。
クエリの内容を少し変えるだけでも、処理速度を大幅に改善できる可能性があるので、ぜひ今日から取り組んでみてください。
SELECT *の使用を控える
SQL Serverに限らず、データベースではSELECT *の含まれるクエリを使わないのが基本です。
クエリ実行時にカラムをすべて取得できるワイルドカード(*)は、その場限りでは使い勝手の良いものかもしれません。
しかし、取得するカラムが多くなればそのぶんデータ量も増えて、クエリ実行の速度も低下します。
テスト中でカラムが少ないうちはまだしも、本番稼働が始まった環境では相当なパフォーマンス低下を招きます。
よってSELECT文を実行する際は、必要なカラムのみに絞りこみましょう。
データの取得が効率よく行われ、クエリの実行速度が改善されるはずです。
WHERE句で関数を使わないようにする
WHERE句に関数で条件を指定すると、検索効率が悪化し、クエリの速度が低下する可能性があります。
関数や計算式を使って、検索条件を詳細に指定するような場面は多くあるでしょう。
しかし、指定の仕方によってはインデックスが有効にならず、全レコードに対して計算を実施してしまうのです。
たとえば以下の関数を実施しても、family_nameはインデックスとして利用されません。
SELECT * FROM member WHERE UPPER(family_name) =’SUZUKI’
なぜなら、SQL Serverのオプティマイザから見れば、family_nameとUPPER(family_name)はまったくの別物であるからです。
family_nameをインデックスとして利用するのであれば、次のようにクエリを記述しなくてはなりません。
SELECT * FROM member WHERE family_name =’SUZUKI’
あるいは、CREATE INDEXでUPPER(family_name)に対して別途インデックスを作成すれば、UPPER関数を使ったままでも想定通り検索が行われます。
検索条件を詳細に指定する際は、SELECT文側に記載するか上記の対応を実施して、クエリ速度の低下を防ぐのが大切です。
BETWEEN句は効果的に使用する
範囲検索は、演算子の組み合わせで事足りるケースもありますが、BETWEEN句を使うことで処理を高速化できるかもしれません。
特に、比較演算子を用いて2つの式を条件に指定するクエリは、代わりにBETWEEN句を使うほうが効率よく検索できます。
【修正前】
SELECT * FROM member WHERE age BETWEEN 20 <= age and age <= 30;
【修正後】
SELECT * FROM member WHERE age BETWEEN 20 and 30;
ただし、BETWEEN句は単体では“以上・以下”の指定しかできない点は、理解しておきましょう。
“より大きい・未満”で範囲を指定する場合は、NOT INを併用してください。
不要なテーブルとの結合を削除する
開発やエラー対応のために結合したテーブルを、そのまま放置してしまうこともあるかもしれません。
しかし、不要なテーブルが結合されていると、WHERE句などで適切に条件を指定しても
クエリの実行に時間を要してしまいます。
「クエリの内容に問題はないのに実行速度がなぜか遅い……」とお悩みであれば、テーブルが結合されていないか確認し、必要に応じて分割してみてください
JOIN句を使う際は工夫する
JOIN句でテーブルを結合したうえで、クエリを実行しなくてはならない場合も当然あります。
その際は、以下のポイントを意識してJOIN句を使いましょう。
JOIN句を使う際に意識したいポイント
- JOIN句で結合する前に条件を絞る
- インデックスが有効なカラム同士で結合する
- ORDER BY句で項目を並び替える
テーブルが結合した状態だと条件の絞りこみにも時間を要してしまうので、先に絞りこんでおくのが効果的です。
また結合する項目に関して、インデックスが有効なものを選ぶ、順番を入れ替えるなどの対応を実施することでも、実行時間の短縮が叶います。
EXISTS句を使用する
WHERE句で条件を指定するものとしてEXISTS句とIN句が存在しますが、基本的には前者を使用するのが理想的です。
EXISTS句は、条件に合致するレコードを見つけた時点で検索が終了するのに対して、IN句は全表検索のうえ合致するものをすべて返します。
そのため、速度の観点だけを考えればEXISTS句を使うのが最適なのです。
とはいえ、IN句でなくてはならないケースも当然あるため、EXISTS句だけを使えばよい、というものでもありません。
チューニングの際はクエリの目的を改めて整理して、EXISTS句で済むものにはそちらを使い、IN句も必要な場面で適宜使うように調整しましょう。
予約語は大文字・小文字のどちらかに統一する
SELECTやFROMなどの予約語を記述する際は、社内やチームで大文字・小文字のどちらを使うか決めておくことも重要です。
同じ内容のクエリでも、大文字・小文字が異なるとデータベースからは異なるクエリとして認識されます。
そのため実行時のキャッシュヒット率が低下し、結果としてデータベース全体の速度低下を招いてしまいます。
微々たる影響かもしれませんが、不安要素は少しでも減らしておくのが賢明です。
また、コーディング規約を統一しておくことで、デバックやチューニングの際の可読性も向上します。
速度改善に直接的には関係ありませんが、作業効率が上がれば、最終的にはデータベースのパフォーマンス向上へとつながります。
インデックスを設定する
クエリの調整だけではなく、適切なカラムへのインデックス設定も、パフォーマンス向上に効果を発揮します。
結合条件に指定されているカラムなどにインデックスを設定すれば、効率よく検索が行われて速度改善が叶います。
テーブルの設計を見直す
クエリを改修しても速度改善が実現しないのであれば、そもそものテーブル設計を見直したほうがよいかもしれません。
たとえば正規化が十分にできていないテーブル設計では、同じデータが繰り返し登場するため、クエリも非効率的になるうえに、ディスクも無駄に圧迫してしまいます。
そのほか、JSONオブジェクトのような非スカラー値が混ざっているのも、検索効率の低下を招くため推奨されていません。
データベースの改修が続くと、いつの間にかテーブル設計が当初の状態から変わっているということもありえるので、定期的に見直して問題があれば改善していきましょう。
バルクインサートを使用する
外部システムとの連携時は、CSVなどのファイル形式でまとめてデータが送付されることも珍しくありません。
そのような場合は、バルクインサートを用いてまとめてレコードを登録するのがおすすめです。
バルクインサートは、複数行のデータを、1度のクエリ実行でまとめてインサートできる機能です。
これを使用すれば、数万レコードにも及ぶ大量のデータでも、時間をかけずにテーブルへ登録できます。
バルクインサートを使う際は、以下のようにクエリを記述してください。
BULK INSERT sample FROM ‘ファイルのパス’ WITH(‘オプション’)
ファイル内の区切り文字や文字形式などはオプション部分で指定可能なので、ある程度柔軟に対応が可能です。
アプリケーション側で条件分岐を行う
クエリを実行する際の条件分岐を、SQL Server側ではなくアプリケーション側で実施するのも一案です。
データベースの役割はデータの取得と更新を行うことであり、条件の複雑な計算までカバーする必要はありません。
そのような処理は“関心の分離”の考えに基づき、アプリケーション側に実装するのが最適です。
クエリの実行に際して複雑な条件分岐が必要になる場合も同様で、SQL Server側は必要最低限の実装に留めて、詳細な処理はアプリケーションに記載しましょう。
役割を分けてSQL Serverでの処理を簡潔にすることで、速度の改善を図れます。
クエリチューニング以外で速度を改善するには
「クエリやテーブル設計に問題はないのに、SQL Serverの動作が重い……」という経験をされた担当者様もいらっしゃるでしょう。
このような場合、基本的にはシステムリソースに問題があると考えられます。
CPUやメモリー、ディスク容量などのシステムリソースが枯渇すれば、SQL Serverのパフォーマンスも低下するというのは想像に難くありません。
具体的な事例としては、ウイルス対策ソフトとの兼ね合いでメモリーが足りていない、ディスクI/Oの性能が要求値を満たしていない、などが挙げられます。
こうした問題に直面した際は、システムリソースの増強を図るのが最善策となることもあります。
すぐに実施できる方法とはいえませんが、クエリチューニングによる改善に限界が見えているのであれば、一考の価値はあるはずです。
関数の使い方やインデックスを見直すことでSQL Serverの処理速度は改善できる
今回は、SQL Serverの代表的な速度改善方法を具体例とともに紹介しました。
WHERE句の条件やインデックスを設定するカラム、またアプリケーションとの設計の兼ね合いなどを見直すことで、SQL Serverの処理速度を向上させることができます。
SQL Serverの要件を見直しても改善がみられない場合は、システムリソースの増強を検討するのも一つの手です。
状況に応じて最適な方法を検討しましょう。
データベースのプロフェッショナルであるコーソルなら、SQL Serverを含め、データベースのパフォーマンスに関する課題を迅速に解決可能です。
SQL Server向けのパフォーマンス監視ツールも取り扱っておりますので、ご興味があればぜひお問い合わせください。