我有一个非常简单的模式的MySQL数据库。有parent
,child
和access
表。MySQL数据库性能调优,模式优化
parent
存储51个字段都是varchar
(其长度从16到512)除了用于4个longtext
字段和主键这是一个bigint
。除主键外,还有其他3个字段的索引。一个以便child
表可以将它作为外键引用。
child
存储23个字段,大多数为varchar
,其中有一些text
字段。 A varchar(256)
字段用作将其链接到父项的外键。不过,外键字段的实际内容预计都会少于60个字符。
accesss
有bigint
场和varchar
场一起构成主键和bigint
领域是它链接到parent
外键。
access
表用于指定哪些用户有权访问parent
中的哪些记录。可能有多个用户应该有权访问任何记录。
有大约在parent
(因此
和周围2E7行。编辑:对不起,access
)2E6行中
child
access
有5329840行。即对于parent
中的每一行,在access
中有一行或多行。
上述架构基于我们希望迁移到MySQL的旧版FileMaker数据库。我相信这不是理想的,但我不知道为什么。
根据参数,查询很快或很慢。所以,例如如果存在bob
有权访问的多条记录,以下查询将需要一两秒钟的时间。查询需要几分钟的时间(如12分钟),不过,如果没有记录该用户bob
访问(例如,如果没有用户名为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 /文本字段的一切?将一个varchar(256)字段用作外键会导致问题(尽管它不在上面的查询中使用)?或者是查询责备?
编辑:我刚刚意识到PRIMARY KEY ("RecordID", "UserName")
的access
表不被用于SELECT ... FROM access WHERE UserName = 'blah'
。我在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)
编辑:@ DRapp的建议确实产生巨大的变化。 access.UserName上的查询很快,有或没有索引。如果我放弃索引并尝试不使用STRAIGHT_JOIN
的DRapp查询,那么它又很慢。
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)
谢谢。之前从未听说过STRAIGHT_JOIN。查找它。 – Wodin 2011-01-24 12:16:21