MySQL
PostgreSQL
RDS
DB
RDB

DBクエリ(RDB)を軽くするためのポイント 性能改善


概要

DB(RDB)を利用するときには、クエリ負荷が性能に大きく関わる。

Webシステムなどで性能を担保するときに、ボトルネックになるのは大体DBクエリになる。

重いクエリによるDBサーバの負荷が高く、システム全体に影響を与えることもしばしば、、

いままでの経験上、DBクエリを軽くするためのポイントを列挙する。

ちなみに当方DBに詳しくない。その中でもできるポイントを記載した。

AWS上のRDSでも同じことなので、このポイントはクラウド上でも使える。

ただ、MySQL/PostgreSQLを触ってきての内容のため、それ以外のRDBでは役に立たないこともあるかも


①DB設計時に気をつけること


SELECTするデータは可能な限り1テーブルから取れるようにする(JOIN回数を減らす設計を)

DB設計時から検討が必要になるが、なるべくシンプルなDB構成にすること。1機能=1テーブルが理想

もちろんRDBである以上、JOINはどうしても出てくる(ユーザ情報からユーザが存在するかなど)

しかし、設計時にある程度考慮して、JOIN回数を減らすようなテーブル設計は可能である

データが大量に発生しそうなところで考慮しておくと効果抜群


採番カラムを入れる(AUTOINCREMENT大事)

こちらも設計時から。割と忘れがち。よくあるユーザと何かの関連情報とかだと、ユーザIDと何かのIDを複合主キーなどにしやすい

ソート時に性能が出なくなるので、明確な理由がなければいれておくべき。

後々、ソート性能が出て非常に助かる


②クエリ作成時に気をつけること


INDEX(インデックス)を都度足すこと

RDB上、避けて通れないINDEX。もちろん設計時に全て考慮ができればいいが、よっぽど熟練した人でないと無理と思う。

実装・試験をしていく中で、遅いSELECTがあればINDEXが貼れるかは都度考慮する

これも割りと後回しにしがち


UNIONよりUNIONALL

クエリ結合にUNIONを使いたい場合がでてくる

できる限り、UNIONALLを利用するべき

UNIONALL・・・結合クエリそのまま

UNION・・・結合したクエリをソート->重複削除(DISTINCT)

UNIONは便利なので、使おうとしがちだが、ソート->重複削除 の処理は非常に重い。

DBを操作するアプリケーション側で処理を肩代わりもできるはずなので、明確な理由がない限りはUNIONは使うべきではない


JOIN対象は絞りを意識する(積算にならないように)

JOINをするときに、「大量データA * 大量データB」 で必要なデータ引っこ抜いてJOINするようなクエリは作らない

「大量データA * Aをぐっと絞る条件」でJOINを考えること

JOINは母体データを極力絞って、処理母体数を減らしていくために使うべき


VIEWをシステム根幹で使わない

VIEWは便利。事前に作っていればクエリの複雑さを解消させる。

ただ、システム全体で何回もJOINするような対象については、VIEWを作成するべきではない

VIEWは汎用的に使えるように検索対象の最大値で組みがちなため、多くのクエリで不要なデータを交えたVIEWから検索することになる

非常に大きな遅延要因になる

また、VIEWでは前述したUNION・UNIONALLを利用しがちなため、UNIONALLを使うこともあてはまる


③試験時に気をつけること


スロークエリをみつける たくさんの軽いクエリよりも一発の重いクエリ

DBサーバに負荷がかかるときは、たくさんの軽いクエリより、一発の重いクエリ

重いクエリを作らないことを重視すること

試験時にスロークエリログを出力するようにして、性能試験を実施するのがよい

-MySQLなら long_query_timeの設定

-PostgreSQLなら log_min_duration_statementの設定

など


繰り返しクエリを実施することで遅延もする

1回だけクエリを通したら早い場合も、繰り返し同じクエリを実行すると負荷が高く、応答遅延の原因になったりする

性能試験などで、繰り返しの試験を実施すべき。共通処理とか何度も通る処理は特に大事


最大値と輻輳制御は必ず考慮すること

非機能用件の話なので、設計に近いかもしれない


最大値

システムのでの各機能における最大値は必ず規定すること。それ以上はエラーではじくが望ましい

規定をしないとどこまでも増えていくデータに対して、性能を考慮することになる


輻輳制御(スケール制御)

規定の許容値を超えないように、処理対応を削減、エラーで返すなど、最大値制御の1つ

TCPなどのネットワークの制御はよくあるが、システム的にも考慮すべき

最近はAWSなどクラウド上で簡単にサーバがオートスケールするので、その対応を代替とすることも良いと思われる

DBもマスター:書き込み、リードレプリカ:読み取りにして、負荷によりスケールさせる

ただ、マスターをスケールすることは結構考慮がいる。シャーデングなど。

そのため、DB負荷が高い場合はエラーを返すなどもあわせて考慮するとよい


まとめ

DBクエリ改善は地道な道。楽な道がない。

データベースに詳しいエンジニアを入れられれば最高だが、アサインできなくても上記の対応をやっておくことでかなり負荷は軽減される。