我想删除数据库中的一行,我有两个选项;首先使用普通列删除行,第二个是主键?
我知道主键更好,但为什么?
答案 0 :(得分:4)
在MySql上,当使用非主键列删除/更新行时,您可能会在多用户环境中遇到奇怪的锁定行为。
这是一个示例 - 两个尝试删除行的会话(禁用自动提交)。
C:\mysql\bin>mysql
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.5.29-log MySQL Community Server (GPL)
Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
mysql> create table test(
-> id int primary key,
-> val int
-> );
Query OK, 0 rows affected (0.02 sec)
......
mysql> select * from test;
+----+------+
| id | val |
+----+------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 6 | 6 |
+----+------+
6 rows in set (0.00 sec)
现在在会话1中,我们将使用主键
mysql> delete from test where id = 5;
Query OK, 1 row affected (0.00 sec)
然后在会话2中我们使用PK删除第2行
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql> delete from test where id = 2;
Query OK, 1 row affected (0.00 sec)
一切看起来都不错 - 会话1删除了行#5,会话2中删除了行#2
现在看看当我们尝试使用非主键删除行时会发生什么:
第一节
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
mysql> delete from test where val = 5;
Query OK, 1 row affected (0.00 sec)
和第2节
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
mysql> delete from test where val = 2;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql>
会话2中的删除命令“挂起”,大约一分钟后它会抛出错误:锁定等待超时
让我们尝试删除其他行:
mysql> delete from test where val = 4;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> delete from test where val = 6;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql>
会话1只删除第5行,而且,逻辑上,锁定应仅放在记录#5上,但是正如您在这些示例中所看到的,当不使用主键时,MySql会将锁定放在上整个表格的所有行。因此,仅使用主键删除行更安全(至少在MySql上)。
答案 1 :(得分:1)
我认为你的意思是这样的陈述:
delete from table
where column = value
当列是主键时,它会自动拥有唯一索引(至少在我知道的数据库中)。这样可以快速找到要删除的记录。
另一个带索引的列几乎一样快,因为它可以使用索引查找。
没有索引的列会慢很多,因为查询必须进行全表扫描。
答案 2 :(得分:1)
主键更好,因为您确定要删除的行:虽然从技术上讲您可以更新主键列,但这样做通常不常见。但是,其他列可以更改,这可能会导致这样的情况:
PK
和另一个唯一标识符,例如email
sample_email@gmail.com
阅读了一行,并决定将其删除simple_email@gmail.com
DELETE USER WHERE email='sample_email@gmail.com'
DELETE
命令不会删除任何内容,因为在您设法运行命令之前已更改了电子邮件。由于PK
不应该改变,因此在正常情况下这种情况是不可能的。当然,您的代码可以检测到没有发生删除,重做读取并重新发出命令,但与使用主键相比,这是一项很多工作。
答案 3 :(得分:0)
行由超级密钥唯一标识,包括候选密钥。主键是一个候选键,但不一定是唯一的键。
为什么主键必须始终是指定更新,删除或其他操作的“更好”方式,这没有根本原因。使用最能表达预期更新的属性,尤其要记住某些属性值可能会发生变化。通常选择主键是因为它是一个不太可能改变的候选键,或者因为它是更新的“首选”标识符。
假设一个表有两个键:j和k,其中k被指定为主键。如果用户实际上想要根据j:DELETE ... WHERE j=123;
的值执行更新,那么根据有效的事务隔离级别和 属性的稳定性,更新可能表达完全不同的意图来自某个时间点基于k的对应值的类似更新。无论哪个属性可能发生变化,都是如此。因此,如果您担心更改键值的影响,那么您应该考虑哪个键选择最能表达用户的预期更新。假设候选键值变化很少,那么使用指定的主键进行所有更新通常是“默认”假设,因为始终使用相同的键会使编码更简单。