2011-01-24 56 views
1

我有一个非常简单的模式的MySQL数据库。有parentchildaccess表。MySQL数据库性能调优,模式优化

parent存储51个字段都是varchar(其长度从16到512)除了用于4个longtext字段和主键这是一个bigint。除主键外,还有其他3个字段的索引。一个以便child表可以将它作为外键引用。

child存储23个字段,大多数为varchar,其中有一些text字段。 A varchar(256)字段用作将其链接到父项的外键。不过,外键字段的实际内容预计都会少于60个字符。

accesssbigint场和varchar场一起构成主键和bigint领域是它链接到parent外键。

access表用于指定哪些用户有权访问parent中的哪些记录。可能有多个用户应该有权访问任何记录。

有大约在parent (因此 access)2E6行中 child 和周围2E7行。编辑:对不起,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) 

回答

1

我一直都很好l在MySQL中使用“STRAIGHT_JOIN”子句,并将主表基础作为第一个排在修饰符列表中。在这种情况下,您的“Access”表寻找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 
+0

谢谢。之前从未听说过STRAIGHT_JOIN。查找它。 – Wodin 2011-01-24 12:16:21