非常に単純なスキーマを持つMySQLデータベースがあります。parent
、、テーブルchild
があります。access
parent
4つのフィールドと。である主キーをvarchar
除いてすべて(長さ16から512の範囲)である51のフィールドを格納します。主キーの他に、他の3つのフィールドにインデックスがあります。テーブルがそれを外部キーとして参照できるようにするための1つ。longtext
bigint
child
child
ほとんどvarchar
がいくつかのtext
フィールドを持つ23のフィールドを格納します。フィールドは、それを親にリンクするvarchar(256)
ための外部キーとして使用されます。ただし、外部キーフィールドの実際の内容はすべて60文字より短いと予想されます。
accesss
には、主キーを構成するフィールドbigint
とフィールドがあり、フィールドはそれをにリンクする外部キーです。varchar
bigint
parent
このaccess
テーブルは、どのユーザーがからどのレコードにアクセスできるかを指定するために使用されますparent
。任意のレコードにアクセスする必要がある複数のユーザーがいる可能性があります。
には約2e6行parent
(したがってがあり、には約2e7行がありaccess
)child
ます。編集:申し訳ありませんが、access
5329840行があります。access
つまり、のすべての行に1つ以上の行がありparent
ます。
上記のスキーマは、MySQLへの移行を検討している古いFileMakerデータベースに基づいています。理想的ではないと思いますが、その理由はよくわかりません。
パラメータに応じて、クエリは高速またはかなり低速になります。bob
したがって、たとえば、にアクセスできるレコードが複数ある場合、次のクエリには1〜2秒かかります。bob
ただし、ユーザーがアクセスできるレコードがない場合(たとえば、呼び出されたユーザーがいない場合)、クエリには数分(たとえば、12分)かかりますbob
。
SELECT
p."RecordID", p."SerialNumber", p."Folder", p."NoteType",
p."FirstName", p."LastName", p."DOB", p."Body", p."From",
p."DateTxt", a."UserName" AS Access
FROM parent AS p
INNER JOIN access AS a ON a."RecordID" = p."RecordID"
WHERE p."RecordID" > 123
AND a."UserName" = 'bob'
ORDER BY p."RecordID"
LIMIT 500;
EXPLAIN
クエリについて次のようになります。
+----+-------------+-------+--------+---------------+---------+---------+---------------------+--------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+---------------------+--------+--------------------------+
| 1 | SIMPLE | p | range | PRIMARY | PRIMARY | 8 | NULL | 731752 | Using where |
| 1 | SIMPLE | a | eq_ref | PRIMARY | PRIMARY | 74 | db.p.RecordID,const | 1 | Using where; Using index |
+----+-------------+-------+--------+---------------+---------+---------+---------------------+--------+--------------------------+
2 rows in set (0.01 sec)
それで、一致しないクエリを高速化する方法はありますか?これは、すべてにvarchar / textフィールドを使用することによって引き起こされる可能性がありますか?varchar(256)フィールドを外部キーとして使用すると、問題が発生しますか(上記のクエリでは使用されていませんが)?それとも、クエリのせいですか?
編集:私はちょうどテーブルPRIMARY KEY ("RecordID", "UserName")
上のがに使用されていないことに気づきました。UserName列にインデックスを作成しましたが、問題が修正されたようです。誰かアドバイスがあれば、それでもありがたいです。access
SELECT ... FROM access WHERE UserName = 'blah'
の現在の出力EXPLAIN
:
+----+-------------+-------+--------+---------------+---------+---------+---------------------+--------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+---------------------+--------+--------------------------+
| 1 | SIMPLE | p | range | PRIMARY | PRIMARY | 8 | NULL | 605020 | Using where |
| 1 | SIMPLE | a | eq_ref | PRIMARY,UNidx | PRIMARY | 74 | db.p.RecordID,const | 1 | Using where; Using index |
+----+-------------+-------+--------+---------------+---------+---------+---------------------+--------+--------------------------+
2 rows in set (0.00 sec)
編集:@DRappの提案は大きな違いを生みます。access.UserNameのインデックスがある場合とない場合で、クエリは高速です。インデックスを削除して、なしでDRappのクエリを試してみると、STRAIGHT_JOIN
再び遅くなります。
access.UserNameにインデックスがないDRappのクエリ:
mysql> explain SELECT STRAIGHT_JOIN p."RecordID", p."SerialNumber", p."Folder", p."NoteType", p."FirstName", p."LastName", p."DOB", p."Body", p."From", p."DateTxt", a."UserName" AS Access FROM access as a, parent AS p where a."UserName" = 'bob' and a."RecordID" > 123 and a."RecordID" = p."RecordID" order by a."RecordID" limit 500;
+----+-------------+-------+--------+---------------+---------+---------+---------------+---------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+---------------+---------+--------------------------+
| 1 | SIMPLE | a | range | PRIMARY | PRIMARY | 8 | NULL | 2382668 | Using where; Using index |
| 1 | SIMPLE | p | eq_ref | PRIMARY | PRIMARY | 8 | bb.a.RecordID | 1 | |
+----+-------------+-------+--------+---------------+---------+---------+---------------+---------+--------------------------+
2 rows in set (0.00 sec)
上のインデックスを持つ同じクエリaccess.UserName
:
mysql> explain SELECT STRAIGHT_JOIN ...;
+----+-------------+-------+--------+---------------+---------+---------+---------------+---------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+---------------+---------+--------------------------+
| 1 | SIMPLE | a | ref | PRIMARY,UNidx | UNidx | 66 | const | 1209780 | Using where; Using index |
| 1 | SIMPLE | p | eq_ref | PRIMARY | PRIMARY | 8 | db.a.RecordID | 1 | |
+----+-------------+-------+--------+---------------+---------+---------+---------------+---------+--------------------------+
2 rows in set (0.00 sec)
access.UserName
インデックスがない場合とない場合の同じクエリSTRAIGHT_JOIN
:
mysql> explain SELECT p."RecordID", p."SerialNumber", p."Folder", p."NoteType", p."FirstName", p."LastName", p."DOB", p."Body", p."From", p."DateTxt", a."UserName" AS Access FROM access as a, parent AS p where a."UserName" = 'zzz' and a."RecordID" > 123 and a."RecordID" = p."RecordID" order by a."RecordID" limit 500;
+----+-------------+-------+--------+---------------+---------+---------+---------------------+--------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+---------------------+--------+----------------------------------------------+
| 1 | SIMPLE | p | range | PRIMARY | PRIMARY | 8 | NULL | 484016 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | a | eq_ref | PRIMARY | PRIMARY | 74 | db.p.RecordID,const | 1 | Using where; Using index |
+----+-------------+-------+--------+---------------+---------+---------+---------------------+--------+----------------------------------------------+
2 rows in set (0.00 sec)