質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Q&A

解決済

3回答

13243閲覧

MySQLの初回クエリの照会パフォーマンスを改善したい

yoshi123

総合スコア28

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

0グッド

1クリップ

投稿2019/02/10 13:08

MySQLの初回クエリが遅い理由と改善方法がわかる方がいれば教示いただけますでしょうか。

下記、例に挙げるテーブルとSQLは一例で、他のテーブルでも同じことが発生しているのですが、SQL_NO_CACHEでクエリキャッシュを使わないようにしても、2回目以降が劇的に早くなります。
同じテーブルの照会でも検索条件(WHERE句)を変えると、また初回は遅くなり、2回目以降は早くなるという具合ですが、WHEREの内容は毎回変わり、初回が0.1sec程度のテーブルなら気にならないのですが、データが多くなるなどで1~2sec以上かかってくると問題がでてきて、どうにか初回から早くしたい、というのが要件なのですが、どのように対応したらよいのでしょうか。

<tagテーブル>
tag_id int
tag varchar(32)

<tagmapテーブル>
id int
tag_id int

のようなテーブルを作って、idに対してタグ付けを行おうとしています。
tagテーブル:100万レコード
tagmapテーブル:10億レコード
でテストデータを作成して、下記SQLを発行してみます。

#'タグ10001'の1回目
SELECT SQL_NO_CACHE id
FROM tagmap tm, tag t
WHERE tm.tag_id = t.tag_id
AND t.tag ='タグ10001';

10000 rows in set (1.79 sec)

#'タグ10001'の2回目
SELECT SQL_NO_CACHE id
FROM tagmap tm, tag t
WHERE tm.tag_id = t.tag_id
AND t.tag ='タグ10001';

10000 rows in set (0.01 sec)

#'タグ50001'の1回目
SELECT SQL_NO_CACHE id
FROM tagmap tm, tag t
WHERE tm.tag_id = t.tag_id
AND t.tag ='タグ50001';

10000 rows in set (1.63 sec)

#'タグ50001'の2回目
SELECT SQL_NO_CACHE id
FROM tagmap tm, tag t
WHERE tm.tag_id = t.tag_id
AND t.tag ='タグ50001';

10000 rows in set (0.01 sec)

のような状況です。

MySQLは5.6です。
物理的なデータファイルも同じものを参照しているはずなので、ディスクのキャッシュなどでもないかと考えているのですが、(再起動後などに)事前に何かクエリを発行してキャッシュを持ったり、バージョンアップなども含めて解決ができればと考えています。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

2回目が早いのは1回目の結果を利用しているからです。
DBMSも、遅いならまだしも、早くて文句を言われる筋合いはないですし。
※追記
8.9.3.2 クエリーキャッシュ SELECT オプション
そもそもSQL_NO_CACHEの意図を取り違えています。
SQL_NO_CACHEはキャッシュの更新をしないという意味で、クエリーキャッシュを無効にするには、query_cache_size システム変数を 0 に設定することです。

解決すべきは1回目に遅い事で、これはチューニングするしかありません。

先ずは、実行計画の内容を確認しましょう。

実行結果からはインデックスは最低あるような気もしますので、以下のようなSQLに変更すると改善されるかもしれません。

SQL

1-- 1 2SELECT id FROM tagmap 3where tag_id in (select tag_id from tag where tag ='タグ10001') 4 5-- 2 6SELECT mp.id 7FROM tagmap mp inner join tag tg 8 on mp.tag_id=tg.tag_id 9where tg.tag ='タグ10001'

質問では1万件ですが、実際にどの程度に絞り込まれるかによりますが、件数次第では必要なインデックスも変わってくると思います。

投稿2019/02/10 13:22

編集2019/02/11 02:09
sazi

総合スコア25184

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yoshi123

2019/02/11 01:24

> 解決すべきは1回目に遅い事で、これはチューニングするしかありません。 まさにそうですね。 SELECT tag_id FROM tag WHERE tag='タグ100000'; が0.00secで返ってきて、 SELECT id FROM tagmap WHERE tag_id=xxxxx; が1~2secなので、ここを改善できればと思います。 が、10億レコードのパフォーマンスとしてはいい方なのかもしれませんね。 > DBMSも、遅いならまだしも、早くて文句を言われる筋合いはないですし。 本番ではまずその通りなのですが、テストではけっこう厄介な問題と考えています。 1回目が通常の(本番同等の)パフォーマンスだとしたときに、テストで毎回WHERE句を変えないといけないという手間が発生し、また、たまたま他のテストで使ったキャッシュを使った誤った結果をパフォーマンスと判断してしまう懸念があります。 ですので1回目を改善したく、正確にパフォーマンスを見ていくのに、キャッシュを使ってほしくない、という状況です。 一方で、最終的な要件としては、本番が早いこと、なので、1回目の結果が妥当だとすれば、全てのパターンの照会結果をキャッシュに載せる、という案も考えており、その手順(再起動時の対応など)と必要なメモリ量も合わせて検討しています。 こちらは別件になりそうなので、別途質問を投稿させていただこうと思います。 もしお知恵があれば、お貸しいただけると助かります。
sazi

2019/02/11 02:08

select での SQL_NO_CACHEは意図した使い方ではありません。 回答に追記したので確認して下さい。
sazi

2019/02/11 02:20 編集

実行計画はどうなっているのでしょう? テーブルスペースを割り当てている資源はどのようなものですか?(HDD?SSD?読み書きの性能は?)
guest

0

初回の照会結果が現環境で妥当として、クラスター構成とパーティションを検討していくことになりました。
いろいろとアドバイスいただきスッキリしました。ありがとうございました。

投稿2019/02/14 13:51

yoshi123

総合スコア28

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

no cache効かないって記事もありますね。
https://code.i-harness.com/ja/q/65b987

ということで2回目はcacheされたレコードが返ってきているかと思われます。

そもそもですが、
10億レコードのテーブルを対象にして
1万件2秒であればそこそこいいパフォーマスだと思います。

どのようなデータかによりますが、
10億レコードも積ませようとする設計に問題があると考えます。

どうしても10億レコード必要であれば、パーティショニングするなど、
物理設計時に別の方法を考えるべきです。

投稿2019/02/10 15:38

szk.

総合スコア1400

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yoshi123

2019/02/11 01:24

> no cache効かないって記事もありますね。 なるほど、そうなんですね。 テスト時には不便ですね、、、 今回のデータは、付与する対象のid(記事、のようなものです)が1000万レコード、各記事に自動で100タグ程度振られる想定で、タグマップを10億、としてテストを行っています。 タグのカテゴリーなどでタグマップをパーティションでN分割した場合、タグ→記事の検索(今の1~2sec)はN分の1になりそうですが、記事→付与されているタグ抽出、では全パーティションを見に行くことになるので、逆に相当に遅くなってしまいそうです。 同じレコードで2つのパーティションテーブルを作って、 タグ→記事用のテーブル(タグでパーティション分割とindex)と、 記事→タグ用のテーブル(記事でパーティション分割とindex)の2つを持つ、などもアリですかね。 同じ10億レコード×2テーブルなのでメンテナンスでトラブルが起こりそうですが、、、 もし同じレコードを重複して持つなら、記事側は記事テーブルにタグカラムを作って、"/"区切りなどで保持するのが現実的かもしれませんね。 ありがとうございました。
sazi

2019/02/11 02:26

>szk.さん 引用されている記事は和訳でもあるし、原文をみるとno cacheを誤解して使用しているのが分かります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問