元ネタはMySQL Casualのslack
それを見て、
- そういや自分も2年前(DB移行時)にこれ調べたなー
- 社内メンバーに改めてちゃんと周知しよう
- なんか記事書くか
という軽い備忘録的な感じ。
ちなみに、揃えないとどうなるか?
slackにもあったように、
インデックスが効かない!(抽出はできる)
試しにテストテーブルを作る(個人の趣味が多分に含まれているのは気にしないこと)
使った環境はMySQL8.0.13
CREATE TABLE `test1` ( `test1_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'testID1', `test1_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '名前', `test1_country` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '出身国', PRIMARY KEY (`test1_id`), KEY `i_test1_1` (`test1_name`), KEY `i_test1_2` (`test1_country`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='test1'; CREATE TABLE `test2` ( `test2_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'testID2', `test2_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '名前', `test2_age` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '年齢', PRIMARY KEY (`test2_id`), KEY `i_test2_1` (`test2_name`), KEY `i_test2_2` (`test2_age`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='test2'; ; CREATE TABLE `test3` ( `test3_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'testID3', `test3_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '名前', `test3_age` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '年齢', PRIMARY KEY (`test3_id`), KEY `i_test3_1` (`test3_name`), KEY `i_test3_2` (`test3_age`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='test2'; ; insert into test1 (test1_name,test1_country) values ('ジョルノ・ジョバァーナ','Repubblica Italiana'); insert into test1 (test1_name,test1_country) values ('ブローノ・ブチャラティ','Repubblica Italiana'); insert into test1 (test1_name,test1_country) values ('レオーネ・アバッキオ','Repubblica Italiana'); insert into test1 (test1_name,test1_country) values ('グイード・ミスタ','Repubblica Italiana'); insert into test1 (test1_name,test1_country) values ('ナランチャ・ギルガ','Repubblica Italiana'); insert into test1 (test1_name,test1_country) values ('パンナコッタ・フーゴ','Repubblica Italiana'); insert into test1 (test1_name,test1_country) values ('トリッシュ・ウナ','Repubblica Italiana'); insert into test2 (test2_name,test2_age) values ('ジョルノ・ジョバァーナ','15'); insert into test2 (test2_name,test2_age) values ('ブローノ・ブチャラティ','20'); insert into test2 (test2_name,test2_age) values ('レオーネ・アバッキオ','21'); insert into test2 (test2_name,test2_age) values ('グイード・ミスタ','18'); insert into test2 (test2_name,test2_age) values ('ナランチャ・ギルガ','17'); insert into test2 (test2_name,test2_age) values ('パンナコッタ・フーゴ','16'); insert into test2 (test2_name,test2_age) values ('トリッシュ・ウナ','15'); insert into test3 (test3_name,test3_age) values ('ジョルノ・ジョバァーナ','15'); insert into test3 (test3_name,test3_age) values ('ブローノ・ブチャラティ','20'); insert into test3 (test3_name,test3_age) values ('レオーネ・アバッキオ','21'); insert into test3 (test3_name,test3_age) values ('グイード・ミスタ','18'); insert into test3 (test3_name,test3_age) values ('ナランチャ・ギルガ','17'); insert into test3 (test3_name,test3_age) values ('パンナコッタ・フーゴ','16'); insert into test3 (test3_name,test3_age) values ('トリッシュ・ウナ','15');
上のSQLの解説
test1テーブルには名前と出身国が、test2とtest3テーブルには名前と年齢が入る。
そして、test2とtest3テーブルに入れるデータは全く同じものを使う。
この後行うのは
test1とtest2,test3テーブルとは名前でJoinするが、この時Collationが異なるとどうなるか?
という簡単な検証である。
そしてEXPLAINしてみると・・・。
Collationがそろってる場合
select test1_name,test1_country,test2_age from test1 inner join test2 on test1_name = test2_name where test1_id = 1 ;
Collationがそろってない(utf8mb4とutf8)場合
select test1_name,test1_country,test3_age from test1 inner join test3 on test1_name = test3_name where test1_id = 1 ;
ちなみに、どっちを実行しようが、以下のような同じ結果が返る。
結果は変わらない。だが、実行計画は大きく違う。
これはデータが少ないうちは気づきにくく、データ量が増えてから「あーーー!!!」となるパターン。