MySql 错误:1175(更新时没有带主键的位置),尽管我确实使用了 PK,并且在查询中没有进行连接

Posted

技术标签:

【中文标题】MySql 错误:1175(更新时没有带主键的位置),尽管我确实使用了 PK,并且在查询中没有进行连接【英文标题】:MySql Error: 1175 (updating without a where with primary key), although I do use the PK, and no joins are made inside the query 【发布时间】:2022-01-06 09:28:13 【问题描述】:

我有这张表(由 mysql 工作台生成):


CREATE TABLE `system_users` (
  `UserNum` int NOT NULL AUTO_INCREMENT,
  `UserName` varchar(45) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
  `UserFullName` varchar(45) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
  `SaveDoc` char(1) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT 'N',
  `MailOnExpire` char(1) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT 'N',
  `ExpirationValue` int DEFAULT NULL,
  PRIMARY KEY (`UserName`),
  UNIQUE KEY `UserNum_UNIQUE` (`UserNum`),
  UNIQUE KEY `UserName_UNIQUE` (`UserName`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

我也有这个带有更新查询的存储过程:

CREATE DEFINER=`root`@`localhost` PROCEDURE `Set_Preferences`(
    IN xUsername        varchar(45),
    IN xSaveDoc         char(1),
    IN xMailOnExpire    char(1),
    IN xExpirationValue int,
)
BEGIN
    UPDATE system_users
       SET SaveDoc         = xSaveDoc,
           MailOnExpire    = xMailOnExpire,
           ExpirationValue = xExpirationValue
     WHERE Username = xUsername;    
END

我确定Username 确实是PK,然后我重新启动了工作台,以防它只是一个临时错误。到目前为止没有运气。

另外,我宁愿不禁用safe mode只是为了摆脱错误,而是要找到并解决实际原因。

谢谢

【问题讨论】:

Edit 问题并包含CREATE 声明system_users @stickybit 完成 嗯,您的CREATE 声明是针对registered_users,而不是system_users。您确定您正在查看正确的表格吗? @stickybit 是的,我确定实际代码是匹配的,我在帖子中将名称替换为 system_users。 【参考方案1】:

在安全更新模式下,即使您的查询引用了表的主键,如果优化器选择执行表扫描或索引扫描,您也会收到错误。

我直接在 MySQL 客户端而不是过程中测试了您的查询,EXPLAIN 报告显示它将使用索引。奇怪的是,当我期望 eq_ref 时,它想以 type: range 的形式运行查询,但我对此没有任何解释。它算作使用了足够多的索引来满足安全更新。

mysql> EXPLAIN UPDATE system_users SET SaveDoc = 'Y',            MailOnExpire = 'Y', ExpirationValue = 2 WHERE username='bkarwin';
+----+-------------+--------------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
| id | select_type | table        | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra       |
+----+-------------+--------------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
|  1 | UPDATE      | system_users | NULL       | range | PRIMARY       | PRIMARY | 137     | const |    1 |   100.00 | Using where |
+----+-------------+--------------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+

无论如何,如果我更改您的过程使其运行EXPLAIN UPDATE 而不是运行UPDATE,我可以看到在过程中运行相同查询时优化器计划有何不同。

mysql> call Set_Preferences('bkarwin', 'Y', 'Y', 123);
+----+-------------+--------------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table        | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra       |
+----+-------------+--------------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
|  1 | UPDATE      | system_users | NULL       | index | NULL          | PRIMARY | 137     | NULL | 2048 |   100.00 | Using where |
+----+-------------+--------------+------------+-------+---------------+---------+---------+------+------+----------+-------------+

文档提到运行表扫描的查询与安全更新模式冲突,但显然我们从这种情况下看到索引扫描也发生冲突。 PRIMARY KEY 上的索引扫描类似于表扫描,因为它将触及每一行。在 UPDATE 的情况下,这意味着它将锁定所有行,即使它实际上并没有更改它们。

我不知道为什么优化器在过程中运行相同的查询时选择进行索引扫描,但在直接运行时使用索引。

我没有强制 UPDATE 使用不同优化计划的解决方法。我只能建议您在调用此过程时禁用安全更新模式。

【讨论】:

谢谢,我想这是由于主键是一个字符串,因此我添加了 UserNum 作为额外的 PK,然后 ``` DECLARE xUserNum int DEFAULT (SELECT UserNum FROM registered_users WHERE UserName = xUserName) ;``` 然后我使用相关的UserNum 而不是UserName 执行更新。

以上是关于MySql 错误:1175(更新时没有带主键的位置),尽管我确实使用了 PK,并且在查询中没有进行连接的主要内容,如果未能解决你的问题,请参考以下文章

带主键的核心数据

mysql 联表查询 巨慢

如何避免 MySQL Workbench 错误代码:此更新期间出现 1175 *无需*禁用“安全更新”

如何查找MySQL中查询慢的SQL语句

Mysql 查询速度慢怎么办

如果mysql里面的数据过多,查询太慢怎么办?