2017-08-31 18 views
1

私たちはMySql 5.5.37、Java 7、およびHibernate 5.1.3を使用しています。 Hibernateはクエリを自動生成しており、私を混乱させるものがあります。私たちは、これらのテーブル...MySqlがテーブルのインデックスを使用していないのはなぜですか?

CREATE TABLE `user` (
    `ID` varchar(32) COLLATE utf8_bin NOT NULL, 
    `FIRST_NAME` varchar(50) COLLATE utf8_bin NOT NULL, 
    `MIDDLE_NAME` varchar(50) COLLATE utf8_bin DEFAULT NULL, 
    `LAST_NAME` varchar(50) COLLATE utf8_bin NOT NULL, 
    `USER_NAME` varchar(50) COLLATE utf8_bin NOT NULL, 
    `URL` varchar(200) COLLATE utf8_bin NOT NULL, 
    `SALUTATION` varchar(10) COLLATE utf8_bin DEFAULT NULL, 
    ... 
    `ADDRESS_ID` varchar(32) COLLATE utf8_bin DEFAULT NULL, 
    PRIMARY KEY (`ID`), 
    UNIQUE KEY `USER_IDX_01` (`USER_NAME`,`URL`), 
    KEY `FK2_USER` (`GRADE_ID`), 
    KEY `FK4_USER` (`USER_DEMOGRAPHIC_INFO_ID`), 
    KEY `FK3_USER` (`CREATOR_ID`), 
    KEY `FK_USER` (`ADDRESS_ID`), 
    CONSTRAINT `FK2_USER` FOREIGN KEY (`GRADE_ID`) REFERENCES `grade` (`ID`), 
    CONSTRAINT `FK3_USER` FOREIGN KEY (`CREATOR_ID`) REFERENCES `user` (`ID`) ON UPDATE NO ACTION, 
    CONSTRAINT `FK_USER` FOREIGN KEY (`ADDRESS_ID`) REFERENCES `cb_address` (`ID`) ON UPDATE NO ACTION 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin | 

role | CREATE TABLE `role` (
    `ID` varchar(40) COLLATE utf8_bin NOT NULL, 
    `NAME` varchar(40) COLLATE utf8_bin NOT NULL, 
    PRIMARY KEY (`ID`), 
    UNIQUE KEY `ROLE_IDX_01` (`NAME`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin | 

を持っていると我々は

user_role | CREATE TABLE `user_role` (
    `USER_ID` varchar(32) COLLATE utf8_bin NOT NULL, 
    `ROLE_ID` varchar(40) COLLATE utf8_bin NOT NULL, 
    UNIQUE KEY `USER_ROLE_IDX_02` (`USER_ID`,`ROLE_ID`), 
    KEY `FK2_USER_ROLE` (`ROLE_ID`), 
    CONSTRAINT `FK1_USER_ROLE` FOREIGN KEY (`USER_ID`) REFERENCES `user` (`ID`) ON DELETE CASCADE ON UPDATE NO ACTION, 
    CONSTRAINT `FK2_USER_ROLE` FOREIGN KEY (`ROLE_ID`) REFERENCES `role` (`ID`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin | 

結合表と一緒にそれらを結合しかし、我々はユーザーのために照会しに役割が含まれている場合私たちのクエリ、MySqlはインデックスを無視しているようです。 Explainプランの "1688568"行に注目してください。 MySQLがインデックスを使用していない理由と、データを照会するためのより良い方法は何ですか?主キーを経由して加入から

mysql> EXPLAIN  select user0_.id as id1_112_, user0_.ADDRESS_ID as ADDRESS17_112_, 
     user0_.AVATAR as AVATAR2_112_, user0_.CREATED_ON as CREATED_3_112_, 
     user0_.CREATOR_ID as CREATOR18_112_, user0_.DOB as DOB4_112_, 
     user0_.ENABLED as ENABLED5_112_, user0_.EXPIRATION as EXPIRATI6_112_, 
     user0_.first_name as first_na7_112_, user0_.GRADE_ID as GRADE_I19_112_, 
     user0_.INCORRECT_LOGINS as INCORREC8_112_, user0_.last_name as last_nam9_112_, 
     user0_.middle_name as middle_10_112_, user0_.password as passwor11_112_, 
     user0_.RESET_STATE as RESET_S12_112_, user0_.salutation as salutat13_112_, 
     user0_.temporary_password as tempora14_112_, user0_.url as url15_112_, 
     user0_.USER_DEMOGRAPHIC_INFO_ID as USER_DE20_112_, user0_.user_name as user_na16_112_ 
    from user user0_ 
    inner join user_role roles1_ ON user0_.id = roles1_.USER_ID 
    inner join role role2_ ON roles1_.ROLE_ID = role2_.ID 
    inner join cb_address address3_ ON user0_.ADDRESS_ID = address3_.id 
    where user0_.url = 'mycityst.myco.org' 
     and (role2_.ID in ('Student')) 
     and lower(address3_.email) = '[email protected]' 
     and user0_.ENABLED = 1; 

+----+-------------+-----------+--------+--------------------------------------+------------------+---------+---------------------------+---------+--------------------------+ 
| id | select_type | table     | type   | possible_keys                        | key              | key_len | ref                       | rows    | Extra                    | 
+----+-------------+-----------+--------+--------------------------------------+------------------+---------+---------------------------+---------+--------------------------+ 
|  1 | SIMPLE      | role2_    | const  | PRIMARY                              | PRIMARY          | 122     | const                     |       1 | Using index              | 
|  1 | SIMPLE      | roles1_   | ref    | USER_ROLE_IDX_02,FK2_USER_ROLE  | FK2_USER_ROLE | 122     | const                     | 1688568 | Using where; Using index | 
|  1 | SIMPLE      | user0_    | eq_ref | PRIMARY,FK_USER                   | PRIMARY          | 98      | schema1.roles1_.USER_ID   |       1 | Using where              | 
|  1 | SIMPLE      | address3_ | eq_ref | PRIMARY                              | PRIMARY          | 98      | schema1.user0_.ADDRESS_ID |       1 | Using where              | 
+----+-------------+-----------+--------+--------------------------------------+------------------+---------+---------------------------+---------+--------------------------+ 

答えて

3

別に、あなたは用語role2_.ID in ('Student'))除く検索条件に使用可能な何のインデックスを持っていません。そのため、MySQLは、インデックスFK2_USER_ROLEを使用しているすべての学生を検索し(そしてそのテーブルで約1.6百万行を見積もる)、テーブルroles1_(テーブルuser_roles)(結合関係role2_.id = roles1_.role_idを介して)から始まり、主キーを介して

where user0_.url='mycityst.myco.org' 
and (role2_.ID in ('Student')) 
and lower(address3_.email)='[email protected]' 
and user0_.ENABLED=1; 

の検索のために、あなたは(あなたがそのテーブルのみに(USER_NAME,URL)にインデックスを持っている)user0_.urlに使用可能なキーが欠落している、とaddress3_.email上の潜在的な指標があるためlower()の使用することはできません - 関数。 (あなたのaddresstableの説明は欠けているので、インデックスがあれば不明です)。

したがって、高速修正版としてuser0_(url)(おそらくenabledを含む)のインデックスを追加します。

また、utf8_binの使用を再考する必要があります。それは 'A'と 'a'を違うとみなします。したがって、大文字と小文字を区別しない検索を実際に行いたい場合は、インデックスを使用できません。通常はメール、名前、住所、またはURLに対して行います。 lower(email)のような関数を使用すると、その列のインデックスも使用できなくなります。可能であれば、列を大文字と小文字を区別しない照合で置き換えてください(例:utf8_unicode_cicicase insensitiveを表します)。

1

その他の問題:IDとroleのNAME以来

は両方とも40文字まで、私はroleテーブルを取り除くことをお勧めしますし、それが起こるどこROLE_NAMEROLE_IDを交換しているようです。

UNIQUE KEYPRIMARY KEYに、user_roleに昇格させてください。

addressテーブルは表示されませんが、照合順序はutf8_binと思われますか?代わりに、それはutf8_unique_ciされていた場合は、インデックス、それを可能性があり、これにより

オプティマイザにクエリを開始するためのより良い方法を与える
and address3_.email = '[email protected]' 

and lower(address3_.email) = '[email protected]' 

を変更。質問については

について

MySQLはインデックスを無視しているようです。 Explainプランの "1688568"行に注目してください。

インデックスを使用しています。テーブルには約 "1688568" "学生"があります。

あなたの本物の質問は、なぜ、より良いテーブルの代わりにroleで始まるのですか?

IN=に、ORINにそれぞれ最適化します。 の場合、オプティマイザはまだ他のインデックスを選択している場合があります。 「インデックスを使用していない」とは、通常、テーブルの〜20%以上がインデックス値によって参照される場合です。

関連する問題