我有一个具有非常简单架构的 MySQL 数据库。有parent
,child
和access
表。
parent
存储 51 个字段varchar
(长度范围从 16 到 512),除了 4 个longtext
字段和主键是 a bigint
。除了主键之外,还有其他 3 个字段的索引。一个以便child
表可以将其作为外键引用。
child
存储 23 个字段,其中大部分是varchar
一些text
字段。varchar(256)
字段用作外键以将其链接到父级。不过,外键字段的实际内容都应少于 60 个字符。
accesss
有一个bigint
字段和一个varchar
字段共同构成主键,该bigint
字段是链接它的外键parent
。
该access
表用于指定哪些用户可以访问 中的哪些记录parent
。可能有多个用户应该有权访问任何记录。
在parent
(因此中有大约 2e6 行,在.中大约有 2e7 行access
)child
。编辑:对不起,access
有 5329840 行。access
即 . 中的每一行都有一行或多行parent
。
上述架构基于我们希望迁移到 MySQL 的旧 FileMaker 数据库。我确信这并不理想,但我不知道具体原因。
根据参数,查询快或慢。因此,例如,如果有多个记录可以bob
访问,则以下查询将需要一两秒钟。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
,那么它又会变慢。
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)
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)