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

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

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

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

Q&A

解決済

2回答

827閲覧

ブランクが多いカラムをJOINする際のインデックスの効かせ方

Rio_1201

総合スコア2

MySQL

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

0グッド

0クリップ

投稿2020/10/09 08:07

編集2020/10/09 09:28

MySQLのバージョンは8.0.17になります。
下記のようなSQLを実行しようとしております。

Mysql

1SELECT * FROM abc_data a 2LEFT JOIN user_data b ON a.abc_code = b.abc_code

こちらを実行するのに現在数分程度かかっております。
それぞれのテーブルのおおよそのレコード数は下記の通りになります。
abc_data:7560行程度
user_data:86000行程度

上記のSQLの実行計画ですが下記の通りとなります。

idselect_typetablepartitionstypepossible_keyskeykey_lenrefrowsfilteredExtra
1SIMPLEaALL7560100
1SIMPLEbALLabc_code87656100Range checked for each record (index map: 0x4)

また、user_dataのabc_codeは
abc_codeあり:3200行程度
abc_codeがブランク:82800行程度
となっております。(abc_codeなしのレコードはabc_codeがnullではなくブランクです。)

user_dataテーブルのabc_codeがブランクが多すぎるせいで
abc_codeのインデックスが使用されずuser_dataのフルスキャンが走るせいでレスポンスが低下していると推測しております。

そこで下記のようにJOINする際にabc_codeを使用するようにしてみました。

Mysql

1SELECT * FROM abc_data a 2LEFT JOIN user_data b FORCE INDEX FOR JOIN (abc_code) ON a.abc_code = b.abc_code

上記の実行結果がこちらになります。

idselect_typetablepartitionstypepossible_keyskeykey_lenrefrowsfilteredExtra
1SIMPLEaALL7560100
1SIMPLEbALLabc_code87656100Range checked for each record (index map: 0x4)

結果、先ほどと変わらずuser_dataのフルスキャンが走る形となっております。

可能であればuser_dataの値を変えたりすることなくインデックスを効かせ
レスポンスを改善させたいのですが、何か方法はございますでしょうか。

不要な情報を全て削ったabc_data,user_dataを作成するSQLは下記になります。
こちらで上述のSQLを実行した際にuser_dataのabc_codeのインデックスを使用し検索が実行したい、という要望になります。

Mysql

1CREATE TABLE `abc_data` ( 2 `rowid` int(11) NOT NULL AUTO_INCREMENT, 3 `abc_code` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '', 4 PRIMARY KEY (`rowid`) USING BTREE, 5 INDEX `abc_code`(`abc_code`) USING BTREE 6) ENGINE = MyISAM AUTO_INCREMENT = 7820 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Dynamic; 7 8INSERT INTO `abc_data` VALUES (1, 'ABCD'); 9INSERT INTO `abc_data` VALUES (2, 'EFGH'); 10INSERT INTO `abc_data` VALUES (3, 'SETH'); 11INSERT INTO `abc_data` VALUES (4, 'EYUK'); 12INSERT INTO `abc_data` VALUES (5, 'ROPN'); 13INSERT INTO `abc_data` VALUES (6, 'SEKB'); 14INSERT INTO `abc_data` VALUES (7, 'HORP'); 15INSERT INTO `abc_data` VALUES (8, 'XKEM'); 16INSERT INTO `abc_data` VALUES (9, 'EOIF'); 17INSERT INTO `abc_data` VALUES (10, 'EMSO');

Mysql

1CREATE TABLE `user_data` ( 2 `userid` int(11) NOT NULL AUTO_INCREMENT, 3 `abc_code` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '', 4 PRIMARY KEY (`userid`) USING BTREE, 5 INDEX `abc_code`(`abc_code`) USING BTREE 6) ENGINE = InnoDB AUTO_INCREMENT = 100400622 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic; 7 8INSERT INTO `user_data` VALUES (1, ''); 9INSERT INTO `user_data` VALUES (2, ''); 10INSERT INTO `user_data` VALUES (3, ''); 11INSERT INTO `user_data` VALUES (4, ''); 12INSERT INTO `user_data` VALUES (5, ''); 13INSERT INTO `user_data` VALUES (6, ''); 14INSERT INTO `user_data` VALUES (7, ''); 15INSERT INTO `user_data` VALUES (8, ''); 16INSERT INTO `user_data` VALUES (9, ''); 17INSERT INTO `user_data` VALUES (10, ''); 18INSERT INTO `user_data` VALUES (11, ''); 19INSERT INTO `user_data` VALUES (12, ''); 20INSERT INTO `user_data` VALUES (13, ''); 21INSERT INTO `user_data` VALUES (14, ''); 22INSERT INTO `user_data` VALUES (15, ''); 23INSERT INTO `user_data` VALUES (16, ''); 24INSERT INTO `user_data` VALUES (17, ''); 25INSERT INTO `user_data` VALUES (18, ''); 26INSERT INTO `user_data` VALUES (19, ''); 27INSERT INTO `user_data` VALUES (20, ''); 28INSERT INTO `user_data` VALUES (21, ''); 29INSERT INTO `user_data` VALUES (22, ''); 30INSERT INTO `user_data` VALUES (23, ''); 31INSERT INTO `user_data` VALUES (24, ''); 32INSERT INTO `user_data` VALUES (25, ''); 33INSERT INTO `user_data` VALUES (26, ''); 34INSERT INTO `user_data` VALUES (27, ''); 35INSERT INTO `user_data` VALUES (28, ''); 36INSERT INTO `user_data` VALUES (29, ''); 37INSERT INTO `user_data` VALUES (30, ''); 38INSERT INTO `user_data` VALUES (31, ''); 39INSERT INTO `user_data` VALUES (32, ''); 40INSERT INTO `user_data` VALUES (33, ''); 41INSERT INTO `user_data` VALUES (34, ''); 42INSERT INTO `user_data` VALUES (35, ''); 43INSERT INTO `user_data` VALUES (36, ''); 44INSERT INTO `user_data` VALUES (37, ''); 45INSERT INTO `user_data` VALUES (38, ''); 46INSERT INTO `user_data` VALUES (39, ''); 47INSERT INTO `user_data` VALUES (40, ''); 48INSERT INTO `user_data` VALUES (41, ''); 49INSERT INTO `user_data` VALUES (42, ''); 50INSERT INTO `user_data` VALUES (43, ''); 51INSERT INTO `user_data` VALUES (44, ''); 52INSERT INTO `user_data` VALUES (45, ''); 53INSERT INTO `user_data` VALUES (46, ''); 54INSERT INTO `user_data` VALUES (47, ''); 55INSERT INTO `user_data` VALUES (48, ''); 56INSERT INTO `user_data` VALUES (49, ''); 57INSERT INTO `user_data` VALUES (50, ''); 58INSERT INTO `user_data` VALUES (51, ''); 59INSERT INTO `user_data` VALUES (52, ''); 60INSERT INTO `user_data` VALUES (53, ''); 61INSERT INTO `user_data` VALUES (54, ''); 62INSERT INTO `user_data` VALUES (55, ''); 63INSERT INTO `user_data` VALUES (56, ''); 64INSERT INTO `user_data` VALUES (57, ''); 65INSERT INTO `user_data` VALUES (58, ''); 66INSERT INTO `user_data` VALUES (59, ''); 67INSERT INTO `user_data` VALUES (60, ''); 68INSERT INTO `user_data` VALUES (61, ''); 69INSERT INTO `user_data` VALUES (62, ''); 70INSERT INTO `user_data` VALUES (63, ''); 71INSERT INTO `user_data` VALUES (64, ''); 72INSERT INTO `user_data` VALUES (65, ''); 73INSERT INTO `user_data` VALUES (66, ''); 74INSERT INTO `user_data` VALUES (67, 'DKEO'); 75INSERT INTO `user_data` VALUES (70, 'DKEO'); 76INSERT INTO `user_data` VALUES (68, 'EMSK'); 77INSERT INTO `user_data` VALUES (69, 'LOES');

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

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

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

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

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

yambejp

2020/10/09 08:22 編集

データ数はすくなくてよいので、かんたんなサンプルを上げてください create table+insertで例示されるとよいでしょう (不要なカラムはばっさり削ってください)
hihijiji

2020/10/09 08:40

サブクエリでブランクレコードを除いてからJOINしてみては?
m.ts10806

2020/10/09 09:45

設計段階から見直したほうがパフォーマンス向上は見込めるかと思いますが、そこは考慮せず食えりだけでなんとかしたいということでしょうか(インデックス再検討もなし?)
Rio_1201

2020/10/09 10:00

設計段階から見直した方がよいというのは最もなのですが 工数の都合上、前任の作ったものを誤魔化しながら対応するしかないのが現状です。 クエリのみ、もしくはインデックスの変更程度で対応することが出来れば、と思っております。
guest

回答2

0

ベストアンサー

そもそもなんで態々空白を入れているんですか?
Nullなら、インデックスの件数も少なくなって早くなりそうですけど。

データを変えずにだと、以下のSQLが遅いようなら改善は難しいと思います。

SQL

1select * from user_data where abc_code > ' '

期待できる速度なら、上記をインラインビューにしたものと結合してみて下さい。

追記

ふと思いつきましたが、空白をNullに置き換えた仮想列を作成し、その仮想列にインデックスを付ければ高速化されるかもしれません。
関数インデックスが使えるバージョンなら、その方が手軽です。

投稿2020/10/09 14:29

編集2020/10/12 02:52
sazi

総合スコア25206

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

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

Rio_1201

2020/10/12 02:35

ありがとうございます。 やはり小手先での解決が難しそうでしたのでわざわざ空白を入れるのをやめNULLで 根本的に解決する方向で対応しようと思います。
sazi

2020/10/12 02:46

思い付きですけど、追記しました。
guest

0

indexを効かせるだけであればabc_dataのインデックスを

INDEX abc_code(abc_code) USING BTREE

をやめて、こうしてください

INDEX `rowid_abc_code`(`rowid`,`abc_code`) USING BTREE

投稿2020/10/09 11:17

yambejp

総合スコア115008

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

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

yambejp

2020/10/09 11:17

ただしこれが高速化につながるかどうかは別の話です
Rio_1201

2020/10/12 02:34

ありがとうございます。 ただ、おっしゃっておられる通りやはり高速化にはつながらず別の方法で対応しようと思います。
yambejp

2020/10/12 02:51

nullにするくらいなら、別テーブルに逃してやれば良いと思います
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問