Ch5. データベースのチューニング
TL;DR
- Webサービスの高速化において、DBのチューニングは最も重要な要素である
- ISUCONにおいても、スコアを伸ばすためにはまずDBのチューニングから行う
- 具体的なアクション:
- インデックスの付与
- N+1の解消
- クエリのキャッシュ設定
- DBへの接続数の設定
Q
- データベースをどのように改善して高速化するのか
- NewSQLとは何か
- DBの負荷計測はどのようにするのか
- インデックスとは何か
- プリペアドステートメントとは何か
- 接続の永続化とは何か
R
NewSQLとは
各種DBの特徴
- RDBMS:一貫性
- NoSQL:自由な形式・高速
- NewSQL:RDBMSとNoSQL両方の性質を併せ持つ
基本はRDBMSを使い、ピンポイントでNoSQLでデータ構造を構成する
DBの負荷計測
- OSから負荷計測する
- topコマンドを使ってCPU使用率をみる
- MySQLのプロセスリストを見る
SHOW PROCESSLIST
でMySQLのスレッドが処理している内容が確認できるState
がSending data
となっているクエリがないか注意する(大量のデータをディスクやメモリから読み取っている可能性があるため)
- pt-query-digestによるスロークエリログの分析
- Percona社がリリースしている、Percona Toolkit(=MySQLの運用・監視・分析に役立つツール群)に含まれるツールの一つ
- mysqldumpslowコマンドよりも詳しい分析ができる
- Debian/Ubuntu系OSではaptコマンドでインストールできる
インデックスとは
- インデックス…索引
- DBでいうインデックスとは、二分探索である
- Bツリーという構造が取られることが多い
- インデックスを付与することで、二分探索を利用して検索することができるようになる
- MySQLでは、EXPLAINステートメントを利用することで、クエリがどのインデックスを利用してデータを取得するかを見ることができる
- オプティマイザと呼ばれる機能が、どのインデックスを利用するかを決定している
- OPTIMIZER_TRACEを利用することでより詳しい情報が得られる
後ほどインデックスについて単体でページを作成する
プリペアドステートメントとは
- 変数を埋め込み可能な形のSQLを発行し、DB側でキャッシュする
- アプリケーション側から変数を送るだけでSQLを発行することができるので、DBの効率が上がる
- SQLの種類ごとに、ステートメントの作成クエリ(PREPARE)と解放クエリ(CLOSE)が必要になるので、Webアプリケーションなどクエリの種類が多いと、通信回数が増えて逆に効率が落ちてしまう
接続の永続化とは
- 一般に、DBに接続する時はTCPやUnix domain socketを介して行われる
- TCPの上からTLSで暗号化をするのが多い
- TCPの接続はコストが高い(3ウェイハンドシェイクで3回通信が必要)、TLSを入れるともっと増える
- -> 一度接続したコネクションを永続化すると効率化できる
- Go言語のMySQLドライバ
go-sql-driver/mysql
ではDB接続に関する設定があるdb.SetMaxOpenConns
:アプリからDBへの最大接続数、デフォルト0(無限大)db.SetMaxIdleConns
:接続をアイドル状態で保持しておく最大件数、デフォルト2- MySQL側では
max_connections
という変数で接続数を制限している。デフォルト151- MySQLでは1つの接続に対して1つのスレッドが割り当てられる
- アイドル状態のコネクションはCPU負荷ほぼ0
max_connections
の値を増やすとコネクション数を増やせるが、その分DBサーバのメモリ負荷も高まる
- アプリ側で
MaxOpenConns
やMaxIdleConns
の値を、リソースを使いすぎず、かつ再接続によるコストが最小限になるような値に設定してあげることが重要