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

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

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

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

MariaDB

MariaDBは、MySQL派生のオープンソースなリレーショナルデータベースシステムです。 また、MySQLとほぼ同じデータベースエンジンに対応しています。

Q&A

解決済

1回答

1851閲覧

フルテキストインデックスで ORDER BY が遅い

nikuatsu

総合スコア177

MySQL

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

MariaDB

MariaDBは、MySQL派生のオープンソースなリレーショナルデータベースシステムです。 また、MySQLとほぼ同じデータベースエンジンに対応しています。

0グッド

0クリップ

投稿2022/02/21 03:53

前提・実現したいこと

フルテキストインデックスでの検索において、ORDER BYを早めたいです。

発生している問題

下記のCREATEに対するSELECTにおいて、ORDER BYがあると約10秒、ないと0.1秒となります。

該当のソースコード

テスト用レコードでmy_contentsには100万件ほどが、my_tag_relationsには1000万件ほどがINSERTされています。

SQL

1CREATE TABLE IF NOT EXISTS my_contents ( 2 ID BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT 3 ,sentences_ID BIGINT(20) UNSIGNED NOT NULL 4 ,is_official TINYINT(1) UNSIGNED NOT NULL DEFAULT 0 5 ,lang_id INT(3) UNSIGNED NOT NULL DEFAULT 0 6 ,count_likes INT(10) UNSIGNED NOT NULL DEFAULT 0 7 8 ,PRIMARY KEY (ID) 9 ,INDEX idx_my_contents_01 (is_official, lang_id, count_likes) 10 ,INDEX idx_my_contents_02 (sentences_ID) 11 ,INDEX idx_my_contents_03 (count_likes, ID) 12); 13 14CREATE TABLE IF NOT EXISTS my_sentences ( 15 ID BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT 16 ,sentence VARCHAR(500) CHARACTER SET utf8mb4 NOT NULL 17 18 ,PRIMARY KEY (ID) 19 ,UNIQUE u_my_sentences_01 (sentence) 20 ,FULLTEXT full_my_sentences_01 (sentence) WITH PARSER ngram 21); 22 23CREATE TABLE IF NOT EXISTS my_tags ( 24 ID BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT 25 ,tag_kind_id INT(3) UNSIGNED NOT NULL DEFAULT 1 26 ,tag_name VARCHAR(500) NOT NULL 27 ,lang_id INT(3) UNSIGNED NOT NULL DEFAULT 0 28 ,is_official TINYINT(1) UNSIGNED NOT NULL DEFAULT 0 29 30 ,PRIMARY KEY (ID) 31 ,INDEX u_my_tags_01 (tag_kind_id, tag_name) 32 ,INDEX idx_my_tags_01 (is_official, tag_kind_id, lang_id) 33 ,INDEX idx_my_tags_02 (tag_name) 34); 35 36CREATE TABLE IF NOT EXISTS my_tag_relations ( 37 tags_ID BIGINT(20) UNSIGNED NOT NULL 38 ,contents_ID BIGINT(20) UNSIGNED NOT NULL 39 40 ,PRIMARY KEY (tags_ID, contents_ID) 41 ,INDEX idx_my_tag_relations_01 (contents_ID) 42 ,CONSTRAINT fk_my_tag_relations_01 FOREIGN KEY (tags_ID) REFERENCES my_tags(ID) 43 ,CONSTRAINT fk_my_tag_relations_02 FOREIGN KEY (contents_ID) REFERENCES my_contents(ID) 44);

上記に対し次のSELECTをしましたが、10秒ほどかかってしまいます。

SQL

1SELECT contents.ID 2 3FROM my_contents contents 4 LEFT JOIN my_sentences sentences 5 ON sentences.ID = contents.sentences_ID 6 LEFT JOIN my_tag_relations tr 7 ON tr.contents_ID = contents.ID 8 LEFT JOIN my_tags tags 9 ON tags.ID = tr.tags_ID 10 11-- 結果は「100 total, Query took 9.2875 seconds. 」と10秒ほどかかってしまいます 12WHERE MATCH (sentences.sentence) AGAINST ('あいうえお' IN BOOLEAN MODE) OR 13 tags.tag_name = 'あいうえお' 14 15GROUP BY contents.ID 16ORDER BY contents.count_likes DESC, contents.ID DESC 17LIMIT 0, 100

試したこと

遅い原因を突き止めるべく上記SELECTEXPLAINを出しましたが、typeAllがあるわけでもなく、これでいいように見えます。

イメージ説明

続いてORDER BYを削除した次のSELECTでは0.1秒ほどになりました。

SQL

1-- 結果は「100 total, Query took 0.1099 seconds.」と0.1秒ほどになりました。 2WHERE MATCH (sentences.sentence) AGAINST ('あいうえお' IN BOOLEAN MODE) OR 3 tags.tag_name = 'あいうえお' 4 5GROUP BY contents.ID 6# ORDER BY contents.count_likes DESC, contents.ID DESC 7LIMIT 0, 100

しかしORDER BYを削除したくはありませんので、残したままで取得を早める方法を探しています。
良い方法ございましたら宜しくお願い致します。

補足情報(FW/ツールのバージョンなど)

MySQLは 5.7 系を使用しています。

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

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

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

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

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

yambejp

2022/02/21 04:03

LEFT JOINで組む必要はあるのでしょうか?
nikuatsu

2022/02/21 06:59 編集

LEFT JOINせずに上記のようなSELECTが実現できるということですか? 例えばどのようになるかご教示頂けませんでしょうか。
yambejp

2022/02/21 07:12

my_contents に対するその他テーブルのリレーションの状況がわからないのでなんとも言えません。 そもそも正規化が必要な状況かどうかも判断できないので
nikuatsu

2022/02/21 07:18

そうでしたか。ありがとうございます。
guest

回答1

0

ベストアンサー

そもそも、以下の認識が正しくありません。

SQL

1GROUP BY contents.ID 2ORDER BY contents.count_likes DESC, contents.ID DESC

group by していない、contents.count_likesをoder by項目に指定しているからです。

投稿2022/02/21 04:08

sazi

総合スコア25195

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

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

nikuatsu

2022/02/21 08:11 編集

どうもありがとうございます。 ORDER BY contents.count_likes DESC, contents.ID DESC に対しては GROUP BY contents.count_likes, contents.ID のように、互いに同じ順序で同じカラムを指定する。 という認識でよろしいでしょうか?
sazi

2022/02/21 17:32

それで大丈夫だと思います。
nikuatsu

2022/02/22 11:53

ありがとうございます。ORDER BY の部分の認識は必須だったようで助かりました。 しかし 'あいうえお' のように存在する値のときはすぐに取得できましたが、'ABCDE' のように存在しない値のときにはやはり10秒ほどかかってしまいました。ORDER BY の部分以外にも原因があるようで、もしお心当たりございましたら宜しくお願い致します。
sazi

2022/02/24 00:22

存在しない語句の場合、FULLTEXTインデックスの全量に対して検索が行われているという事になります。 その場合の実行計画を確認してみてください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問