我有一个非常简单的架构的MySQL数据库。有parent
,child
和access
表格。
parent
存储51个字段,这些字段全部为varchar
(长度范围为16到512),但4个longtext
字段除外,主键为bigint
。除主键外,还有其他3个字段的索引。一,以便child
表可以将其称为外键。
child
存储23个字段,其中大多数varchar
包含一些text
个字段。 varchar(256)
字段用作将其链接到父级的外键。但是,外键字段的实际内容都应该短于60个字符。
accesss
有一个bigint
字段和一个varchar
字段组成主键,bigint
字段是将其链接到{{1}的外键}}
parent
表用于指定哪些用户可以访问access
中的哪些记录。可能有多个用户可以访问任何记录。
parent
(因此和parent
)access
中的2e7行左右有2e6行。编辑:对不起,child
有5329840行。即access
中的每一行access
都有一行或多行。
上述架构基于我们希望迁移到MySQL的旧FileMaker数据库。我确信这不太理想,但我不确切知道为什么。
查询速度很快或相当慢,具体取决于参数。所以,例如如果parent
有多个记录可以访问,则以下查询将花费一两秒钟。但是,如果没有用户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
那么,有没有办法加速不匹配的查询?这可能是因为varchar / text字段用于所有内容吗?使用varchar(256)字段作为外键会导致问题(尽管在上面的查询中没有使用它)?或者是责备的查询?
编辑:我刚刚意识到+----+-------------+-------+--------+---------------+---------+---------+---------------------+--------+--------------------------+
| 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)
表上的PRIMARY KEY ("RecordID", "UserName")
未用于access
。我在UserName列上创建了一个索引,似乎解决了问题。如果有人有建议,我仍然会感激。
SELECT ... FROM access WHERE UserName = 'blah'
的当前输出:
EXPLAIN
编辑:@ DRapp的建议确实有很大的不同。无论是否有access.UserName上的索引,查询都很快。如果我删除索引并在没有+----+-------------+-------+--------+---------------+---------+---------+---------------------+--------+--------------------------+
| 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的查询,那么它又会变慢。
DRapp的查询没有访问索引.UserName:
STRAIGHT_JOIN
与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
答案 0 :(得分:1)
我一直很幸运使用MySQL中的“STRAIGHT_JOIN”子句,并将主表基础作为限定符列表中的第一个。在这种情况下,您的“访问”表寻找Bob,然后查看Bob有权查看的记录。如果它在ACCESS查询失败,则无需深入查看。此外,由于连接基于相同的“RecordID”,我已经更改了对“a”的引用。表。由于此查询首先基于用户名,因此我也会有一个密钥。我对它的解释和表现也感兴趣。
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