1

非常に単純なスキーマを持つMySQLデータベースがあります。parent、、テーブルchildがあります。access

parent4つのフィールドと。である主キーをvarchar除いてすべて(長さ16から512の範囲)である51のフィールドを格納します。主キーの他に、他の3つのフィールドにインデックスがあります。テーブルがそれを外部キーとして参照できるようにするための1つ。longtextbigintchild

childほとんどvarcharがいくつかのtextフィールドを持つ23のフィールドを格納します。フィールドは、それを親にリンクするvarchar(256)ための外部キーとして使用されます。ただし、外部キーフィールドの実際の内容はすべて60文字より短いと予想されます。

accesssには、主キーを構成するフィールドbigintとフィールドがあり、フィールドはそれをにリンクする外部キーです。varcharbigintparent

このaccessテーブルは、どのユーザーがからどのレコードにアクセスできるかを指定するために使用されますparent。任意のレコードにアクセスする必要がある複数のユーザーがいる可能性があります。

には約2e6行parent (したがってaccessがあり、には約2e7行がありchildます。編集:申し訳ありませんが、access5329840行があります。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列にインデックスを作成しましたが、問題が修正されたようです。誰かアドバイスがあれば、それでもありがたいです。accessSELECT ... 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)
4

1 に答える 1

1

MySQLで「STRAIGHT_JOIN」句を使用し、修飾子のリストの最初にプライマリテーブルベースを配置することは、常に幸運でした。この場合、「アクセス」テーブルでボブを探し、次にボブがアクセスできるレコードを確認します。ACCESSクエリで失敗した場合は、詳しく調べる必要はありません。さらに、結合は同じ「RecordID」に基づいているため、「a」への参照を変更しました。テーブル。このクエリは最初にユーザー名に基づいているので、私もそれにキーを持っています。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
于 2011-01-24T11:44:54.690 に答える