0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

DB周りのパフォーマンスチューニングに関して

Last updated at Posted at 2020-08-10

書籍を読んだので補足しつつ備忘録…
読んだ書籍はこちら
https://www.amazon.co.jp/%E3%83%97%E3%83%AD%E3%81%A8%E3%81%97%E3%81%A6%E3%81%AESQL%E3%83%81%E3%83%A5%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0%E5%85%A5%E9%96%80-%E7%A6%8F%E7%94%B0-%E6%AD%A6%E5%BF%97/dp/4797336080

パフォーマンスチューニングとは

処理時間が遅いシステムを早くすること。
と一言で言ってしまうのは簡単なのですが、では何をどうすればよいのかという話
DB周りに集中して紹介します。

ボトルネックの調査

開発環境では往々にしてデータ数が少なく、本番に出した瞬間に重すぎてやばい、ということが起こり得ます。
本番のDBをダンプしたり、psqlなら本番で\timingを使うなどして心配なクエリを修正した方が得策です

よくある原因

よく原因になりそうなところと解決策を書いていきます
実験に使うテーブルは
レコード数: およそ1000万件
インデックス:update_dateにのみ貼られている
とします。

インデックスが貼られていない

よく取得するカラムにインデックスが貼られていないと、びっくりするくらいレスポンスが遅くなることがあります。
インデックスに関しては、
https://qiita.com/Ohtak/items/8089b8d1fe58ae52cc9d
でも書いたのでよければそちらもどうぞ
ただインデックスを貼る目安は、
全体のデータ量の10%~15%未満のデータを取ってくるとき
だそうなので、全部をselectするようなときには当てはまらない時もあります。
ちなみにpsqlで、


select
  id
from
  test_table
where
  update_date >= current_timestamp + CAST(-96 || 'hour' AS interval);

というクエリを投げた場合の実行時間は、(抽出数の平均は0.1%未満でした)

update_dateにインデックスあり:24848.563ms
update_dateにインデックスなし:108.471 ms

という結果だったので、これだけでかなり早くなります。

インデックスを貼っていないカラムでソートしている

DBにおいて、ソートは時間のかかる処理ですが、それに対してjavaでソートする方が早く済むことがあります。


select
  id
from
  test_table
order by
  create_date;

というクエリの実行時間は15016.297 msですが、


long start = System.currentTimeMillis();
List<Integer> idList = testDao.select();
Collections.sort(idList);
long stop = System.currentTimeMillis();
System.out.println("実行にかかった時間は " + (stop - start) + " ミリ秒です。");

の実行結果は13036msと、わずかにjavaで実行した方が早い結果となりました。
また、インデックスを貼ったカラムはつねにソートされた状態で格納されているため、


select
  id
from
  test_table
order by
  update_date;

では9075.452msという結果になります。
データ量やインデックスを貼っている/貼っていない、その後の処理で何をやるかによって
全体を吟味しながら使い分けた方がよさそうです。

不要なカラムを取ってきている


select
  id
from
  test_table;

select
  *
from
  test_table;

の二つを比べた際、

idだけselect      :5346.993 ms
全てのカラムをselect:12002.372 ms

という結果になりました。
必要な時でなければ、「とりあえず全部のカラムをとってきとけ」というのは避けた方がよいかも?
(ただ、カラムを一つ取り出すのも二つ取り出すのもSQLの処理的には同じ(はず)なので、単にデータ量がメモリを圧迫してただけとかの可能性もあります。)

頻繁に呼び出すデータのキャッシュが作られていない

たとえインデックスが貼られていても頻繁に呼び出されすぎる、あるいは他が重くなった時問題になることがあります。
マスタデータなど、それほど更新されないデータはキャッシュにしてしまいましょう

まとめ

いろいろ書きましたが、まとめると
・テストするときは本番環境に近づけよう
・インデックスを正しく貼ろう
・必要なデータだけとってこよう
となります。
当然のことを言っているようですが、システムを拡張する際など、意識していないとやらかすときがあるため気をつけましょう。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?