1

我有一个具有非常简单架构的 MySQL 数据库。有parent,childaccess表。

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 (因此access中有大约 2e6 行,在.中大约有 2e7 行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 列上创建了一个索引,这似乎已经解决了这个问题。如果有人有建议,我仍然会很感激。accessSELECT ... 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)
4

1 回答 1

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
于 2011-01-24T11:44:54.690 回答