MySQL数据库性能调优,模式优化

时间:2011-01-24 09:44:15

标签: sql mysql performance indexing schema-design

我有一个非常简单的架构的MySQL数据库。有parentchildaccess表格。

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 (因此parentaccess中的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

1 个答案:

答案 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