深入理解Mysql——schema设计与大表alter操作

相关文章:
深入理解Mysql——高性能索引与高性能SQL
深入理解Mysql——锁、事务与并发控制(辟谣)
深入理解Mysql——schema设计与大表alter操作
mysql explain-output 译文

数据类型

整数与小数类型

整数类型有如下几种:
TINYINT(1个字节),SMALLINT(2个字节),MEDIUMINT(3个字节),INT(4个字节),BIGINT(6个字节)。

小数(实数)类型有如下几种:
FLOAT4个字节)、DOUBLE(8个字节)、DECIMAL(占用字节更多)。

**DECIMAL(n,m)**表示仅允许保留m位小数;n表示小数点左右两边数字总和。也就是说只允许n-m个整数位。

字符串类型

varchar是使用最频繁的字符串类型,它除了维护字符串还维护了一个或者两个字节用来记录长度。varchar(n),n代表单个字符的个数

当我们设置varchar(5)或者varchar(100)来存储 “mysql",哪个会更好呢?当然是varchar(5)更好,因为varchar(100)即使之存储5个字符的字符串,也会分配100个字符的内存空间,特别是当使用临时表会更不好。

char用来存储较小的字符串 char(n)代表可以存储n个字符的字符串。

blob 与text
这两种类型是用来存储较大字符串的类型,与其他类型不同,它们的排序只按照最前边max_sort_length个字符进行排序,而不是按照全部字符排序。因此如果只需要按照较小的字符排序,可以缩小max_sort_length的设定。或者使用 order by substring( column,length)进行排序。

enum
用时可以使用 enum(“string1”,“string2”,“string3”)代替varchar\char等字符串类型。

enum类型对字符,实际是使用整数进行存储的,并且当对enum列排序也是按照实际存储的整数值排序。适合存储如有序的状态,性别等等。

比如,我们新增一个enum类型的列,并按照主键id依次顺序插入:


ALTER TABLE USER ADD  enumType ENUM("apple","banana","orange");


ALTER TABLE USER ADD  enumType ENUM("apple","banana","orange");


UPDATE `user`.`user` SET `enumType` = 'apple' WHERE id=1;
UPDATE `user`.`user` SET `enumType` = 'banana' WHERE id=2;
UPDATE `user`.`user` SET `enumType` = 'orange' WHERE id=3;

SELECT id,(enumType+0) AS a FROM USER ;

OUTPUT:
id	enumType
1	1
2	2
3	3

可以看到,插入的 “apple”,“banana”,"orange"分别使用 1,2, 3进行存储,也就是按照enum设定的顺序。当然对这个enum列的排序也是按照数字排序。

注意:因此我们在使用enum类型的时候,切记不要存储 如 enum(“10”,“29”,“42”,“99”)这有 的字符串类型的数字,以避免产生不必要的混淆!

enum类型
优点:更紧凑的存储,更加节省空间;
不足:当enum类型的列 与 varchar类型的列进行关联时比两个varchar进行关联慢一些。

日期与时间

DATETIME
datetime 用来表示日期,范围从1001年到9999年,精确到秒:YYYYMMDDHHMMSS,占用8个字节。这种类型与时区无关。

TIMESTAMP
从1970.1.1以来的描述,跟UNIX时间戳相同。
占用4个字节,也是精确到秒,但是范围要比DateTime小很多,1970~2038。
另外,这种类型默认not null,首次插入会自动用当前时间填充。

FROM_UNIXTIME()可以把时间戳转为日期。
UNIX_TIMESTAMP()可以把日期转为时间戳。

对于比秒更小的粒度:目前暂无支持,可以使用bigint存储更小的时间戳。

数据类型优化技巧
1、数据类型更小通常更好,数据类型越简单越好
2、数值操作比字符操作快,小类型的处理速度比大类型快
3、尽量避免使用NULL,要是有必要用NULL,那也可考虑使用0来进行代替
4、IP用int存:inet_aton()、inet_ntoa()

范式设计

第一范式:要求有主键,并且要求每一个字段原子性不可再分
第二范式:要求所有非主键字段完全依赖主键,不能产生部分依赖
第三范式:所有非主键字段和主键字段之间不能产生传递依赖

第一范式:要求有主键,并且要求每一个字段原子性不可再分

第一范式很好理解,首先要确保每一行都有主键存在,另外每一列都要有不可拆分的业务对象。

-- -违反范式一 userContact 中是“手机号,qq号”
"cid"	"userContact"
"2"		"15472152456,502327342"
"3"		"13676574456,7702322"

修改为:

"cid"	"phone"	"qqNumber"
"1"		"15472152456"	"502327342"

第二范式:要求所有非主键字段完全依赖主键,不能产生部分依赖
即满足第一范式前提,当存在多个主键的时候,才会发生不符合第二范式的情况。比如有两个主键,不能存在这样的属性,它只依赖于其中一个主键,这就是不符合第二范式。通俗理解是任意一个字段都只依赖表中的同一个字段。(涉及到表的拆分)

第三范式:所有非主键字段和主键字段之间不能产生传递依赖
请看下边的例子:

"cid"	"role"				"phone"			"qqNumber"			"level"
"1"		"programmer"		"15472152456"	"502327342"			"6"
"2"		"manager"			"15372152456"	"534232"			"2"
"3"		"manager"			"15372152436"	"5023272"			"3"

这个设计就违反了第二范式,因为level字段依赖于role,role依赖于cid:
cid 为1的员工 programmer 角色 级别为6;
cid 为2的员工 manager级别 级别为2;
cid 为3的员工 manager级别为3

-- - 符合第二范式:

"cid"	"phone"			"qqNumber"
"1"		"15472152456"	"502327342"
"2"		"15372152456"	"534232"
"3"		"15372152436"	"5023272"

"cid"	"role"			"level"
"2"		"manager"		"3"
"3"		"manager"		"2"
"1"		"programmer"	"6"

换个例子,比如一个表中有 年龄\是否未成年 ;这两个字段明显存在依赖。

范式设计的优缺点

优点:
1.拆分的更细,冗余数据更少
2.占用空间更小,可以更好的放入内存,操作更快

缺点:
会导致查询需要频繁使用多表关联,会导致执行效率降低、并且有些索引无法很好执行。

反范式设计的优缺点

优点:
把所有业务相关的字段尽可能的放入一张表中,避免多表关联查询。
单表可以更好的使用索引,有时候执行效率更高!
缺点:
更多的冗余数据,导致更新或者删除缓慢。

反范式常用的冗余设计

  1. 基于静态变更频率不高数据的冗余
    静态数据指相关字段变更频率不高,如用户资料,可作冗余字段
    以消息表为例
    Fuid,Tuid,Msg,Dateline
    范式化设计后,在内容呈现上可能需要涉及多表关联,因为用户想知道发消息的人是谁?
    那么,可增加冗余字段:Funame
  2. 基于谓词的冗余
    有些where连接条件很热门,一个谓词为多个SQL服务,那么,我们可以把这些热门的谓词收集,集中存在到一张冗余表
    以用户登录为例子,假设有上亿条用户资料并做了分表处理,用户只关心uname,根据uname需要到各个分表去查询uid,此时,我们可按:uname,uid建立冗余表
  3. 基于聚会函数的冗余
    频繁的count,max,sum等需求,例如,论坛今日发帖总量,可建立冗余字段Spost
  4. 基于排序的冗余
    索引用来加速查询或者已经是件家喻户晓的事,但还有一个优势,即:降低排序成本。
    仍然以消息表为例,若我们按uname对消息做排序的代价估计会蛮高的,但如果在消息表里把uname冗余并且建立好索引,则可以借助索引来抵消排序

大表的Alter操作

之前处理过多个千万级别的表的alter操作,竟然跑脚本跑了一两天才跑完。下面总结一下Alter大表的几种方式:

  • 现在一个不提供服务的数据库表中进行执行alter脚本,执行完毕后与提供服务的主库进行切换。当然要最大限度保证这两个库的数据是同步的。
  • 影子拷贝:通过重命名替换表

创建一个张影子表,新增需求字段,同步数据,同步一致后通过原子性的重命名操作替换两个表。

-- step1
CREATE TABLE User_new LIKE USER;
-- step2
alter table User_new add column;//增加字段
--step3
同步数据,直到一致
-- step4 原子替换
RENAME TABLE USER TO User_old ,User_new TO USER
  • 在一个不提供服务的同步从库中执行alter,然后主从切换
<think>嗯,用户这次在询问MySQLALTER语句的具体用法,包括语法、示例和常见操作。用户可能正在学习数据库管理或者需要解决实际的数据结构修改问题,情绪应该是比较急切想要获取实用信息的。从用户提供的三个引用来看,[1]提到ALTERTABLE语法结构和IGNORE选项,[2]详细介绍了添加列等操作并强调了源代码示例,[3]则需求无关涉及的是SELECT语法。这说明用户真正需要的是[2]中提到的增删改列等核心操作指导。上次系统级指令要求数学达式规范但本次问题无关,不过需要保持中文回答并生成相关问题。用户显然更关注实践操作而非理论,所以示例代码要详实,分类要清晰。考虑到用户可能遇到的真实场景,我打算把ALTER操作分成结构修改、数据修改、性能优化和用户管理四个维度展开。在示例准备上,增删列这类基础操作要展示全字段定义,而修改数据类型要特别强调INT到VARCHAR可能丢失数据的风险——这是运维常见痛点。RENAMETABLE这种冷门但救命的操作也得包含,很多用户不知道单条命令就能避免锁问题。注意到引用[1]提到IGNORE选项,这个要重点解释,因为它在处理重复记录时能避免整个语句失败。而引用[2]没有提到的COLLATE设置对于多语言用户很重要,得补充进示例。最后生成的问题要覆盖进阶需求:性能部分涉及在线DDL工具,实战难点包括修改方案,这些在真实运维中都是高频问题。三个引用里有两个混用了"MysqL"和"MySQL"的小写,但用户查询时用的是标准"MySQL",所以术语要保持标准拼写。</think> 以下详细介绍MySQLALTER语句的核心用法、语法规范及实用示例(基于MySQL 8.0+): --- ### 📚 **ALTER语句核心语法结构** ```sql ALTER [IGNORE] TABLE alter_specification [, alter_specification] ... ``` **关键参数说明**: - `IGNORE`:遇重复数据时跳过错误(慎用) - `alter_specification`:具体修改操作,支持**30+种结构变更操作** --- ### 🛠 **高频操作详解示例** #### 1️⃣ **增删修改列** | 操作类型 | 语法示例 | 说明 | |----------------|--------------------------------------------------------------------------|---------------------------------------------------------------------| | **添加新列** | `ALTER TABLE users ADD COLUMN age INT NOT NULL DEFAULT 0 AFTER username;` | 在`username`后添加整型列`age`,非空且默认值为0 | | **删除列** | `ALTER TABLE users DROP COLUMN birth_year;` | 删除列`birth_year` | | **修改列定义** | `ALTER TABLE users MODIFY COLUMN email VARCHAR(100) UNIQUE;` | 扩展邮箱字段长度至100并添加唯一约束 | | **重命名列** | `ALTER TABLE users CHANGE COLUMN phone mobile CHAR(11);` | 将`phone`列重命名为`mobile`并修改数据类型为定长字符串 | #### 2️⃣ **主键/索引管理** ```sql -- 添加主键 ALTER TABLE orders ADD PRIMARY KEY (order_id); -- 添加联合唯一索引 ALTER TABLE products ADD UNIQUE INDEX idx_name_price (product_name, price); -- 删除索引 ALTER TABLE logs DROP INDEX idx_created_at; ``` #### 3️⃣ **结构优化** | 操作场景 | 示例 | 效果 | |----------------|-----------------------------------------------------------------------|---------------------------------------------------------------------| | **重命名** | `ALTER TABLE old_orders RENAME TO archived_orders;` | 安全迁移数据 | | **引擎变更** | `ALTER TABLE user_logs ENGINE = InnoDB;` | MyISAM转InnoDB(需停机维护) | | **字符集转换** | `ALTER TABLE comments CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;` | 解决emoji存储问题 | #### 4️⃣ **约束管理** ```sql -- 添加外键约束 ALTER TABLE order_items ADD CONSTRAINT fk_order_id FOREIGN KEY (order_id) REFERENCES orders(order_id) ON DELETE CASCADE; -- 删除外键约束 ALTER TABLE order_items DROP FOREIGN KEY fk_order_id; ``` #### 5️⃣ **自动增长重置** ```sql -- 重置自增主键起始值 ALTER TABLE invoices AUTO_INCREMENT = 10000; ``` --- ### ⚠️ **关键注意事项** 1. **操作风险** - 添加索引/修改列可能导致锁(使用`ALGORITHM=INPLACE`可优化) - 建议使用`pt-online-schema-change`工具实现不停机维护 2. **数据备份强制要求** > **生产环境执行ALTER前必须备份数据** - 误操作可能导致数据永久丢失[^2]。 3. **数据类型兼容性** - VARCHAR扩长度可在线操作 - CHAR转TEXT需要重建(触发锁) --- ### 📝 **综合操作示例** ```sql -- 用户结构调整案例 ALTER TABLE users ADD COLUMN wechat VARCHAR(50) COMMENT '微信ID' AFTER email, MODIFY COLUMN password CHAR(64) NOT NULL COMMENT 'SHA256加密密码', DROP INDEX idx_username, ADD UNIQUE INDEX idx_login (email, mobile), RENAME COLUMN register_time TO create_time; ``` --- 📚 **进阶参考文档**: [MySQL 8.0 ALTER TABLE语法手册](https://dev.mysql.com/doc/refman/8.0/en/alter-table.html) --- ### ❓ **相关问题** 1. **如何避免ALTER TABLE时的长时间锁?** 2. **修改亿级结构有哪些实践方案?** 3. **`ALTER TABLE ... ALGORITHM=INSTANT`支持哪些操作类型?** 4. **如何监控ALTER TABLE的进度?** [^1]: MySQL官方ALTER语法基础结构 [^2]: MySQL ALTER语句操作风险指南
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值