MySQL无主键表查找

本文探讨了MySQL中无主键表可能带来的问题,包括查询效率降低、维护困难以及主从延迟等,并提供了查询无主键表的SQL语句。建议为表显式定义主键以优化存储和提高性能。同时,分享了解决主从延迟的临时方案以及如何为无主键表添加主键的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:

在 MySQL 中,建表时一般都会要求有主键。若要求不规范难免会出现几张无主键的表,本篇文章让我们一起揪出那个无主键的表。

1.无主键表的危害

以 InnoDB 表为例,我们都知道,在 InnoDB 中,表都是根据主键顺序以索引的形式存放的,这种存储方式的表称为索引组织表。一张 InnoDB 表必须有一个聚簇索引,当有主键时,会以主键作为聚簇索引;如果没有显式定义主键,InnoDB 会选择一个唯一的非空索引代替。如果没有这样的索引,则 MySQL 自动为 InnoDB 表生成一个隐含字段作为主键。

也就是说,最好我们可以显式定义主键,那么无主键表可能会产生哪些危害呢?首先没有主键就意味着无法用到主键索引,可能影响查询效率。其次是对维护不友好,比如想升级为 MGR 集群或使用某些开源工具时,都会要求表要有主键。还有一点,对于无主键的表批量更新或删除,极易引起很长时间的主从延迟。

这里也顺便提下,当主库对于无主键表(特别是既无主键又无索引的表)大量更新或删除时,从库会发生极大的主从延迟,甚至会一直卡着执行不下去,别问我怎么知道的,前段时间遇到过。发生这种情况的现象是从库延迟不断增大,且正在执行的主库 binlog pos 位点一直不变,这个时候需要去主库解析下从库卡着的 binlog pos 位点,发现是对某个无主键表的操作,这时若想从库尽快赶上,可以手动设置下忽略该表的同步,处理 SQL 如下:

# 假设检查发现是 testtb 表导致了主从延迟 可以再从库忽略该表的同步
mysql> STOP SLAVE SQL_THREAD;
Query OK, 0 rows affected (0.00 sec)

mysql> CHANGE REPLICATION FILTER REPLICATE_IGNORE_TABLE = (db.testtb);
Query OK, 0 rows affected (0.00 sec)

mysql> START SLAVE SQL_THREAD;
Query OK, 0 rows affected (0.01 sec)

忽略掉该表的同步后,从库很快就会追上主库了。后续可以为该表增加主键,然后再手动同步下并解除忽略即可。

2.找到无主键的表

言归正传,当我们的数据库实例中有好多好多张表时,又应该如何查找是否有无主键的表呢?总不能一个个找吧,聪明的你可能想到了,可以从 MySQL 自带的系统表中查找,因为我们的所有建表信息都存储在系统库 information_schema 中。下面 SQL 可以查找出无主键的表:

# 查找某个库中无主键的表(有唯一键无主键的表也会被查出)
SELECT
	t1.table_schema,
	t1.table_name
FROM
	information_schema.TABLES t1
LEFT OUTER JOIN information_schema.TABLE_CONSTRAINTS t2 ON t1.table_schema = t2.TABLE_SCHEMA
AND t1.table_name = t2.TABLE_NAME
AND t2.CONSTRAINT_NAME IN ('PRIMARY')
WHERE
	t2.table_name IS NULL
AND t1.table_type = 'BASE TABLE'
AND t1.TABLE_SCHEMA = 'testdb';

# 查找整个实例中无主键的表
SELECT
	t1.table_schema,
	t1.table_name
FROM
	information_schema.TABLES t1
LEFT OUTER JOIN information_schema.TABLE_CONSTRAINTS t2 ON t1.table_schema = t2.TABLE_SCHEMA
AND t1.table_name = t2.TABLE_NAME
AND t2.CONSTRAINT_NAME IN ('PRIMARY')
WHERE
	t2.table_name IS NULL
AND t1.table_type = 'BASE TABLE'
AND t1.TABLE_SCHEMA NOT IN (
	'information_schema',
	'performance_schema',
	'mysql',
	'sys'
);

找到了无主键的表,下一步就是为表新增主键了,无论你使用自增 id ,uuid ,或其他算法生成的主键字段,都建议为表新增主键。以自增 id 为例,我们可以为无主键的表这样新增主键:

# 为表 tb1 新增自增ID字段作为主键
ALTER TABLE tb1 ADD COLUMN inc_id INT UNSIGNED NOT NULL auto_increment COMMENT '自增主键' PRIMARY KEY FIRST;

# 查找到的无主键表 拼接出新增主键的SQL
SELECT
CONCAT('ALTER TABLE ',t1.table_schema,'.',t1.table_name,' ADD COLUMN inc_id INT UNSIGNED NOT NULL auto_increment COMMENT \'自增主键\' PRIMARY KEY FIRST;')
FROM
	information_schema.TABLES t1
LEFT OUTER JOIN information_schema.TABLE_CONSTRAINTS t2 ON t1.table_schema = t2.TABLE_SCHEMA
AND t1.table_name = t2.TABLE_NAME
AND t2.CONSTRAINT_NAME IN ('PRIMARY')
WHERE
	t2.table_name IS NULL
AND t1.table_type = 'BASE TABLE'
AND t1.TABLE_SCHEMA NOT IN (
	'information_schema',
	'performance_schema',
	'mysql',
	'sys'
) ;

总结:

本篇文章主要介绍了无主键表可能会产生的危害及如何查找是否存在无主键的表。文中的一些 SQL 都是根据系统表来查找的,各位可以保存下到自己的环境试试看哦。MySQL 中的表还是强制要求有主键才好,人要有主见,表也要有主键!

<think>好的,我需要回答用户关于如何在MySQL中修改主键的问题。首先,根据用户提供的引用内容,特别是引用[1]、[2]、[4],这些引用详细描述了修改主键的步骤,包括移除旧主键、添加新主键以及处理复合主键的情况。我需要将这些步骤整理成一个清晰的流程,同时注意潜在的问题和注意事项。 首先,确认用户的需求是修改现有的主键,可能包括更改主键字段或转换为复合主键。根据引用[2]和[4],修改主键通常需要三个主要步骤:删除旧的主键约束,修改字段属性(如果需要),然后添加新的主键。需要注意的是,如果原主键是自增的,可能需要先移除自增属性,如引用[2]中的例子所示。 另外,引用[4]提到在修改主键为复合主键时,必须确保新的主键组合是唯一的,否则会导致错误或数据丢失。因此,备份数据是一个关键步骤,这在所有操作前都是必须的,如引用[4]中的备份示例。此外,用户可能需要检查现有数据是否有重复,以避免添加新主键失败,这里可以参考引用[5]的方法来查找重复数据。 接下来,我需要将步骤结构化,确保逻辑清晰,并涵盖不同的情况,比如单个主键改为另一个字段,或者转换为复合主键。同时,需要强调注意事项,例如数据备份、字段约束检查等。可能还需要提到在修改主键后可能需要调整相关的索引或外键约束,但根据现有引用,用户提供的资料中没有提到这些内容,因此可能不需要深入讨论。 最后,确保回答使用中文,遵循格式要求,行内数学达式用$...$,独立公式用$$...$$,虽然在这个问题中可能用不到数学公式,但需要保持整体结构正确。同时,生成相关问题,参考示例中的结构,提出与修改主键相关的其他问题,如性能影响、处理重复数据等。 总结步骤: 1. 备份数据 2. 删除旧主键 3. 处理自增属性(如果有) 4. 添加新主键(单字段或复合) 5. 验证数据一致性 需要确保每个步骤都有对应的引用支持,并在回答末尾添加引用标识。同时,语言要简洁明了,避免技术术语过于复杂,适合不同层次的用户理解。</think>### 如何在 MySQL 中修改主键? 修改 MySQL 主键需要谨慎操作,以下是详细步骤和注意事项: --- #### **步骤 1:备份数据** 在修改主键前,**必须备份数据**以防止操作失误导致数据丢失。 ```sql -- 创建备份 CREATE TABLE 名_backup LIKE 原名; INSERT INTO 名_backup SELECT * FROM 原名; ``` [^4] --- #### **步骤 2:删除原有主键** 若已有主键,需先删除原有主键约束: ```sql ALTER TABLE 名 DROP PRIMARY KEY; ``` **注意**: - 如果原主键字段是自增属性,需先移除自增(仅限单字段主键): ```sql ALTER TABLE 名 MODIFY 字段名 数据类型 NOT NULL; ``` [^2] --- #### **步骤 3:添加新主键** 根据需求添加新的主键,支持**单字段主键**或**复合主键**: 1. **单字段主键** ```sql ALTER TABLE 名 ADD PRIMARY KEY (新字段名); ``` 2. **复合主键** ```sql ALTER TABLE 名 ADD PRIMARY KEY (字段1, 字段2); ``` **前提条件**: - 新主键字段必须满足**非空(NOT NULL)**约束[^3]。 - 复合主键的组合值必须唯一,否则添加时会报错[^4]。 --- #### **步骤 4:验证和调整** 1. **检查结构**: ```sql DESCRIBE 名; ``` 2. **处理重复数据**: 若添加主键时因重复数据失败,可通过以下语句查找重复项: ```sql SELECT 字段1, 字段2, COUNT(*) FROM 名 GROUP BY 字段1, 字段2 HAVING COUNT(*) > 1; ``` [^5] --- #### **注意事项** 1. **数据一致性**:修改主键可能影响关联的外键或索引,需同步调整。 2. **性能影响**:大操作可能耗时,建议在低峰期执行。 3. **自增主键**:若需为新主键添加自增属性,需在添加主键后单独设置: ```sql ALTER TABLE 名 MODIFY 字段名 INT AUTO_INCREMENT; ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值