MySQLが遅いと思ったときにやること


1.はじめに
1年近くサボってた弊技術ブログですが、zennデビューしたということで、こちらにも同じ記事を載せて見ます。
今回はこちらの記事と同じ内容です。

MySQLで検索や更新などを行っているときに「このクエリ遅いなー」と思ったときにどういう流れで解決を図るか、自分なりの定石(?)です。
ちなみに、MySQLのバージョンは8.0を前提に記載しています。

2.スロークエリログ

まずはやはりこれ。でもそもそも出力される設定になっていないと見ることもできません。なので、出力される設定にしておきましょう。
設定ファイル(Windowsならmy.ini、MacまたはLinuxならmy.cnf)の[mysqld]のセクションに以下の設定を入れる必要があります。

slow_query_log=ON
long_query_time=2
slow_query_log_file=slow.log

1つ目はスロークエリログ出力の有無で、ONにする必要があります。
2つ目は実行に何秒以上かかったらスロークエリとするかの判定基準です。どれくらいにするかはDBをどういう使い方をするかにもよるけど、自分は大体2〜3秒くらいが多いかも。
3つ目は出力するログファイルの名前。ここはわかりやすい名前にするのがいいでしょう。

スロークエリログの見方については、こちらあたりを参考にして見てください。
絶対見るのは実行したSQLとかかった時間(Query_time、Lock_time)で、それ以外に探索したレコード数、ヒットしたレコード数とか状況に応じて必要な情報を、といったところでしょうか。

3.EXPLAIN

スロークエリログの次に見るのがEXPLAIN。MySQL Workbenchなどで遅くなっているSQLの前にEXPLAIN をつけて実行すると、実行計画(クエリをどうやって実行するか)を出力してくれます。
実行計画の見方はこちらあたりが参考になると思います。
例えば、typeのところにALLやindexがあったらインデックスがうまく使われていないんだなとかがわかると思います。

4.インデックス

上記に書いたインデックスですが、さすがに今時インデックスを全く貼らないという人はあまりいないと思いますが、それでもただ闇雲に貼ればいいというわけではありません。
例えば、TRUEまたはFALSEのみしか入らないカラムに貼ってもほとんど意味はないです。後、値がよく変更されたり新たな値が入ったり消されたりするカラムに貼るのもお勧めできないです(全体的に重くなるので)。
貼るべき箇所はレコードによって一意またはいろいろな値が入るカラムで、かつ検索条件やORDER BYのソートキー、あるいはJOINの結合条件になることが多いカラムに貼るのがいいでしょう。

後、カラムに対して何らかの演算を行なったり、後方一致や中間一致(前方一致はOK)のLIKEで検索を行う場合はインデックスが効かなくなるので注意が必要です。
あるカラムに何らかの演算を行うようなSQLを頻繁に実行する場合は演算結果をGenerated Columns(仮想列)としてテーブルに持っておいて、それにインデックスを貼るやり方もあります。Generated Columnsについてはこちらを参考にして見てください。

5.その他クエリチューニング

よく言われるのが、

SELECT * FROM CUSTOMER;

のようにワイルドカードを使うのではなく、

SELECT id, name, age FROM CUSTOMER;

のように必要なカラムだけを指定するとかです。
後はJOINする時は結合対象のテーブルをWHEREで絞り込んでから結合するとかサブクエリが複雑になりすぎている時は一旦バラしてサブクエリを使わずにできるか検討するとかでしょうか。

6.パラメータチューニング

スロークエリログのところでも出てきたmy.iniまたはmy.cnfのパラメータでパフォーマンス改善に寄与できるところはいくつかあります。
例えばinnodb_buffer_pool_sizeを大きくしてメモリにキャッシュできるサイズを大きくする(マシンのメモリサイズの7〜8割が目安と言われています)などがあります。
こちらの記事に詳しい情報が記載されています。

7.終わりに

こんな感じでスロークエリの改善と一言で言っても、いろいろなアプローチがあります。自分もまだまだSQLチューニングについては勉強することがあると実感しますが、手を加えて遅いクエリが早くなった時は何とも言えない充実感があります。
皆さんも高速化手法を覚えて、MySQLライフを楽しみましょう!

Tramoriesその1 開発環境構築(SpringBoot, MySQL)

前回の記事で個人開発でWebサービスを作るのを目標にすると書いて、1ヶ月以上経ってしまったorz
というわけでまずは環境構築(Macを前提にしています)。まずはサーバーサイドから。

1. MySQL
まだインストールしていない方はこちらが参考になると思います。
自分はすでにインストールしていましたが、下記のようなエラーが出るので、こちらを参考に解決を図る。

すると次は下記のエラーになったので、こちらを参考にしてみる。

そうしたら、解決!記事を書いてくれた方に感謝!m(__)m

その後は下記のSQLでユーザー、データベース、権限を作成。

CREATE DATABASE tramories;
CREATE USER tramories IDENTIFIED BY ‘*******’;
GRANT ALL ON tramories.* TO 'tramories'@'localhost' IDENTIFIED BY ‘*******’;

2. Spring Boot
データベースを作った次は、Spring Bootの環境構築。
Spring Bootの環境構築にはSpring Initializrというとても便利なサイトがあるので、これを使います。
自分はProject : Maven, Language : Java, Spring Boot : 2.5.0で作りました。
DependenciesはSpring Boot DevTools, Spring Web, Lombok(自動的にゲッターとセッターを作ってくれるので、すごく便利!), Thymeleaf, Spring Security, OAuth2 Client, Spring Data JPA, Flyway Migration, MySQL Driver, Spring Batchを入れました(他にも何か入れたかも)。

その後は大雑把に以下の流れ。
1. application.propertiesに必要な設定を追加
2. ログインユーザー用のサービス、エンティティ、リポジトリを作成し、Flywayでユーザーテーブルとレコードを作成
3. 簡単なログインページを作成し、ログインできるところまで確認

詳細は後日GitHubにアップするので、そちらを見ていただければと。

次回はフロントエンド(React)の環境構築をやります。

2021個人開発Webサービス案

明けましておめでとうございます。2021年もよろしくお願いします。

さて、今年の目標の1つとして、今年こそ個人のWebサービスを開発しようと思っています。
開発しようと思っているサービスと、使う予定の技術はざっと以下のような感じです。

サービス名
 Tramories トラモリーズ(travel + memories

サービス概要
旅の写真(昔の写真も含む)を共有し合うサービス

サービス詳細
投稿機能(写真+簡単な説明)、タグ、コメント、いいね、ユーザーフォロー
 OAuth2認証(検討中)オススメ機能(検討中)

一般的なミニSNSっぽい感じですが、

使用技術
 サーバーサイド
  JavaSpring Boot(機械学習を入れる場合はPythonFlask
Laravelを使うかかなり迷ったけど、今仕事で使っていることだし、Spring Bootにしようかと。
機械学習でおすすめ機能とかスパムフィルターとか取り入れるんだったら、Flaskで機械学習API作るのもありかなと思ったり。

 フロントエンド
  TypeScriptReact
フロントエンドのフレームワークはこれかなと。JavaScriptで行くかTypeScriptにするかは若干迷っているけど。

 データベース
  MySQL
ここはこうなるか。PostgreSQLは一度も触ったことがないんで。最近流行りのNoSQLも今回はいいかなと。

 Webサーバー
  Apache
ここもこれしかないか。Nginxも最近は増えてきているようだけど、Apacheで。

 インフラ
  Microsoft AzureHerokuなども検討中)
ここが一番の悩みどころ。以前AzureにWordpress入れたら1ヶ月で6000円とかしてすごい焦ったもんなあ。
誰かWebサービスを安くデプロイする方法を知っている方教えていただけるとありがたいです。

ドキュメント、その他
 画面仕様書、テーブル定義書、機能設計書(処理フローなど)、単体テスト仕様書、結合テスト仕様書
個人サービス作る場合ってドキュメントとか公開するものなのかなあ?公開しないにしても仕事の練習になるだろうし、作ろうとは思っています。

少しづつ作って行って、何とか年内には公開したいなあ。

久々にローカル環境で作業したときにたまにやりがちなこと

とりあえずphp artisan make:migrationでマイグレーションファイル作って、さあphp artisan migrateと打って、

あれ??

https://qiita.com/hondy12345/items/d32ed749fb49e9da7de6
MySQLのサーバー立ち上げてなかった(汗)