私は非常にシンプルなスキーマを持つMySQLデータベースを持っています。 parent
,child
およびaccess
のテーブルがあります。MySQLデータベースのパフォーマンスチューニング、スキーマの最適化
parent
店舗4つのlongtext
フィールドとbigint
一次キーのを除いて(16から512までの長さの範囲の)全てvarchar
ある51のフィールド。主キーの他に3つのフィールドにインデックスがあります。 1つは、child
テーブルがそれを外部キーとして参照できるようにすることです。
child
は、ほとんどがvarchar
で、フィールド数がtext
の23のフィールドを格納します。 A varchar(256)
フィールドは、それを親にリンクするための外部キーとして使用されます。ただし、外部キーフィールドの実際の内容はすべて60文字未満になると予想されます。
accesss
は一緒に主キーを構成するbigint
フィールドとvarchar
フィールドを持ち、bigint
フィールドがparent
にリンクする外部キーです。
access
テーブルは、どのユーザーがparent
からどのレコードにアクセスできるかを指定するために使用されます。任意のレコードにアクセスする必要がある複数のユーザーがいる可能性があります。
parent
(したがって
にし、access
)
child
で2E7行の周り2E6行の周りにあります。編集:申し訳ありません、access
5329840行があります。つまり、parent
の行ごとに1つ以上の行がaccess
にあります。
上記のスキーマは、私たちがMySQLに移行しようとしている古いFileMakerデータベースに基づいています。私はそれが理想的ではないと確信していますが、私は正確になぜそれを知りません。
クエリは、パラメータによって高速またはかなり遅くなります。したがって、たとえば次のクエリは、bob
がアクセスできるレコードが複数ある場合は、1〜2秒かかります。 (bob
と呼ばれるユーザが存在しない場合、例えば)、ユーザーbob
がアクセス権を持っていることをレコードがない場合、クエリは、しかし、(例えば12分)、数分かかります。
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)フィールドを使用すると問題が発生します(ただし、上記のクエリでは使用されていません)。または、クエリに責任がありますか?
編集:私はちょうどSELECT ... FROM access WHERE UserName = 'blah'
のテーブルのPRIMARY KEY ("RecordID", "UserName")
が使用されていないことを認識しました。 UserName列にインデックスを作成しましたが、問題が修正されているようです。誰かアドバイスがあれば、私はまだそれを感謝します。 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)
EDIT:DRappの提案@大きな違いを生むん。クエリはaccess.UserNameのインデックスの有無にかかわらず高速です。私がインデックスを削除し、STRAIGHT_JOIN
なしでDRappのクエリを試してみると、それは再び遅くなります。
access.UserName上のインデックスのないDRappのクエリ:access.UserName
上のインデックスを持つ
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)
同じクエリ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)
ありがとうございました。以前はSTRAIGHT_JOINのことは聞いたことがありません。それを見て。 – Wodin
@Wodin、ええ、それはオプティマイザに伝えます、私のためには考えません、私はテーブルとジョイン条件を置く順序を知っています...そのシーケンスを使用してください。ルックアップテーブルへの15以上のジョインで、1400万行以上のデータを持つことができました。オプティマイザは、より小さいテーブルを使用して1400万以上のテーブルに戻ってきて、チョークしました。 – DRapp
はい、ありがとう、私は知っている:)私はあなたの答えをupvoted。私が他の答えを得たかどうかを確認するのを待ってから答えてください。例えば私はまだvarchar/textのようにすべてのフィールドにかなりの影響があり、またvarchar(256)フィールドを外部キーとして使用するかどうかはひどいことです。私はこの1つ前にまだ答えられていない1つの質問を残しましたが、その回答はゼロであり、振り返ってみるとおそらくstackoverflowに属しません。だから私は4つの質問をしたので、私の受け入れは現時点で50%です。私はこの質問に回答した時点で75%まで上がります – Wodin