繁体   English   中英

mysql数据库表中的pkey

[英]pkey in mysql database table

通过这个SQL语句,我试图理解pkey的用法,我们已经有复合键作为主键,有人可以解释一下。

CREATE TABLE categories_products (
    category_id int unsigned not null,
    product_id int unsigned not null,
    PRIMARY KEY (category_id, product_id),
    KEY pkey (product_id),
    FOREIGN KEY (category_id) REFERENCES categories (id)
       ON DELETE CASCADE
       ON UPDATE CASCADE,
    FOREIGN KEY (product_id) REFERENCES products (id)
       ON DELETE CASCADE
       ON UPDATE CASCADE
);

通过扩展的解释,并从您的示例开始:

首先,让我们设置环境:

mysql>
mysql> create table categories_products (
    ->   category_id int unsigned not null,
    ->   product_id int unsigned not null,
    ->   somefield varchar(25),
    ->   primary key (category_id, product_id)
    -> );
Query OK, 0 rows affected (0.10 sec)

mysql>
mysql> insert into categories_products(category_id, product_id) values (1, 1), (1, 2), (2, 2);
Query OK, 3 rows affected (0.05 sec)
Records: 3  Duplicates: 0  Warnings: 0

我删除了外键,因为它们对此没有任何影响,并且我添加了一个附加字段,因为它使结果更易于解释。 之后,我将对此进行扩展。

首先,我们尝试查询特定类别:

mysql> explain select * from categories_products where category_id = 1;
+----+-------------+---------------------+------+---------------+---------+---------+-------+------+-------+
| id | select_type | table               | type | possible_keys | key     | key_len | ref   | rows | Extra |
+----+-------------+---------------------+------+---------------+---------+---------+-------+------+-------+
|  1 | SIMPLE      | categories_products | ref  | PRIMARY       | PRIMARY | 4       | const |    2 |       |
+----+-------------+---------------------+------+---------------+---------+---------+-------+------+-------+
1 row in set (0.00 sec)

从结果中我们可以看到它确实是在使用PRIMARY键,并且只检查了2行,因为索引知道这就是所有与where约束匹配的东西。

我们的下一个测试同时查询产品和类别:

mysql> explain select * from categories_products where category_id = 1 and product_id = 1;
+----+-------------+---------------------+-------+---------------+---------+---------+-------------+------+-------+
| id | select_type | table               | type  | possible_keys | key     | key_len | ref         | rows | Extra |
+----+-------------+---------------------+-------+---------------+---------+---------+-------------+------+-------+
|  1 | SIMPLE      | categories_products | const | PRIMARY       | PRIMARY | 8       | const,const |    1 |       |
+----+-------------+---------------------+-------+---------------+---------+---------+-------------+------+-------+
1 row in set (0.00 sec)

再一次,我们可以看到正在使用PRIMARY键,但这一次更好,它只返回一行。

接下来,让我们尝试仅查看产品:

mysql> explain select * from categories_products where product_id = 1;
+----+-------------+---------------------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table               | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+---------------------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | categories_products | ALL  | NULL          | NULL | NULL    | NULL |    3 | Using where |
+----+-------------+---------------------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)

这次,查询无法找到合适的索引来使用,因此不得不使用where来缩小结果范围。 这比它能够执行索引查找的效率低。

为什么会这样呢? 为什么优化程序甚至在复合索引中都使用category_id而不使用product_id 因为MySQL从左到右读取该索引。 考虑一个大的复合指数(f1, f2, f3, f4) 这隐式地使您可以访问这些其他索引(f1)(f1, f2)(f1, f2, f3)

现在让我们在其中添加pkey索引,看看会发生什么。

mysql> create index pkey on categories_products(product_id);
explain select * from categories_products where product_id = 1;
Query OK, 0 rows affected (0.17 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql>
mysql> explain select * from categories_products where product_id = 1;
+----+-------------+---------------------+------+---------------+------+---------+-------+------+-------+
| id | select_type | table               | type | possible_keys | key  | key_len | ref   | rows | Extra |
+----+-------------+---------------------+------+---------------+------+---------+-------+------+-------+
|  1 | SIMPLE      | categories_products | ref  | pkey          | pkey | 4       | const |    1 |       |
+----+-------------+---------------------+------+---------------+------+---------+-------+------+-------+

到此为止,现在也可以使用索引来执行与以前相同的查询。

现在,我为什么要添加一个附加字段。 当主键覆盖整个表时(如在这种情况下那样),任何查询都将从索引而不是表中读取整个结果,这可能会在解释结果中产生误导性的条目。 例如,如果我删除该附加字段和pkey索引,然后重新运行查询,则结果如下:

mysql> explain select * from categories_products where product_id = 1;
+----+-------------+---------------------+-------+---------------+---------+---------+------+------+--------------------------+
| id | select_type | table               | type  | possible_keys | key     | key_len | ref  | rows | Extra                    |
+----+-------------+---------------------+-------+---------------+---------+---------+------+------+--------------------------+
|  1 | SIMPLE      | categories_products | index | NULL          | PRIMARY | 8       | NULL |    3 | Using where; Using index |
+----+-------------+---------------------+-------+---------------+---------+---------+------+------+--------------------------+
1 row in set (0.00 sec)

现在乍看之下似乎正在使用PRIMARY索引,但是在仔细检查后,我们看到它仍在检查整个表(3行),并将结果限制在where以及索引中。

无论如何,这就是为什么您需要在product_id上建立索引的原因

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM