SQL使用及注意事项

一、数据类型选择规范

1.IP 地址存储

推荐方式:使用 INT UNSIGNED + INET_ATON() / INET_NTOA()

sql 复制代码
CREATE TABLE access_log (
    id BIGINT AUTO_INCREMENT,
    ip_int INT UNSIGNED NOT NULL COMMENT '用户IP(整数存储)',
    PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 插入
INSERT INTO access_log(ip_int) VALUES (INET_ATON('192.168.1.100'));

-- 查询
SELECT INET_NTOA(ip_int) AS ip FROM access_log;

优势

节省空间(4 字节 vs VARCHAR(15) 的 15+ 字节)

支持高效范围查询(如 WHERE ip_int BETWEEN ... 判断 IP 段)
注意

必须用 UNSIGNED,否则高位为 1 的 IP(如 192.168.x.x)会转为负数

IPv6 不支持!若需支持 IPv6,请用 VARBINARY(16) + INET6_ATON()(MySQL 5.6.3+)

补充建议

若业务未来可能支持 IPv6,不要用 INT 存 IP,改用 CHAR(39) 或 BINARY(16) 统一处理。

2. 时间类型选择

类型 存储大小 范围 时区 推荐场景
DATETIME 8 字节 '1000-01-01 00:00:00' ~ '9999-12-31 23:59:59' 需要超大时间范围(如历史档案)
TIMESTAMP 4 字节 '1970-01-01 00:00:01' ~ '2038-01-19 03:14:07' 自动转为 UTC 存储,查询转回 session 时区 绝大多数业务场景(日志、订单、用户行为)
INT UNSIGNED 4 字节 0 ~ 4294967295(≈2106年) 高并发写入、需极致性能(如埋点)

推荐

优先用 TIMESTAMP(自动时区转换、节省空间)

超高频写入场景(如每秒万级) → 用 INT + UNIX_TIMESTAMP():

sql 复制代码
INSERT INTO event_log(event_time) VALUES(UNIX_TIMESTAMP());
SELECT FROM_UNIXTIME(event_time) FROM event_log;

注意:TIMESTAMP 在 MySQL 8.0 中默认不自动更新,需显式指定:

sql 复制代码
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP

二、字符集与排序规则(重点/普遍)

  • 统一使用 utf8mb4 (不是 utf8 !)

    • utf8 在 MySQL 中是阉割版(最多 3 字节),无法存 emoji(如 👍、❤️)
    • utf8mb4 支持完整 4 字节 UTF-8
  • 排序规则推荐 utf8mb4_general_ci(快)或 utf8mb4_unicode_ci(准)

  • 必须保证:库、表、列三级字符集一致,避免隐式转换导致索引失效

sql 复制代码
-- 建库
CREATE DATABASE myapp DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

-- 建表(显式指定)
CREATE TABLE user (...) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

三、索引设计规范

1. 索引类型

  • InnoDB / MyISAM:仅支持 B+Tree(即 BTREE)
  • MEMORY:可选 HASH(等值快)或 BTREE(范围/排序快)

2. 联合索引最左前缀原则

sql 复制代码
-- 查询:WHERE a=1 AND b=2 ORDER BY c
-- 最佳索引:KEY idx_abc (a, b, c)

3. 覆盖索引优化

sql 复制代码
-- 只查索引字段,避免回表
SELECT user_id, create_time FROM user WHERE username = '张三';
-- 索引:KEY idx_username_cover (username, user_id, create_time)

4. 禁止滥用索引

  • 单表索引数 ≤ 5 个(写多读少场景更少)
  • 高频更新字段慎加索引(如 update_time

四、事务与批量操作

1. 事务大小控制

  • 单事务操作行数 ≤ 1000 行
  • 批量任务每批后 SLEEP(1~5) 秒,避免主从延迟、binlog 积压

2. 自增主键并发控制

  • INSERT 并发 ≤ 200 线程(避免自增锁竞争)
  • 高并发插入考虑:
    • 批量 INSERT INTO ... VALUES (...), (...), ...
    • 使用 innodb_autoinc_lock_mode=2(MySQL 5.7+)

五、排序、分组、去重优化

操作 建议
ORDER BY 尽量程序端排序;若 DB 排序,确保走索引且结果集 < 1000 行
GROUP BY 同上,避免 Using temporary; Using filesort
DISTINCT 优先用 GROUP BY 替代,或确保字段有索引

关键原则
WHERE 过滤后结果集 > 1 万行时,禁止在 DB 层做排序/分组!

六、线上高危 SQL 禁令

禁止项 原因 替代方案
UPDATE/DELETE ... LIMIT N 主从执行顺序不一致 → 数据错乱 ORDER BY PK,或程序分页更新
关联子查询(尤其 UPDATE/DELETE 中) 性能 O(N²),极易拖垮 DB 改为 JOIN 或程序端处理
存储过程 / 函数 / 触发器 / 视图 难以监控、扩展性差、逻辑分散 全部移至应用层
INSERT ... ON DUPLICATE KEY UPDATE 高并发下主从不一致(auto_inc 锁问题) 改用 SELECT + INSERT/UPDATE 两步(加分布式锁)
多表联表更新 UPDATE t1, t2 SET ... 语法模糊、易锁表、难优化 拆分为单表更新 + 程序关联

特别强调
所有业务逻辑必须在应用层实现,数据库只负责"可靠存储"和"高效检索"。


七、补充:其他最佳实践

1. 字段命名规范

  • 小写 + 下划线:user_id, create_time
  • 布尔字段用 is_xxxxxx_flagis_deleted, review_status
  • 避免关键字:不用 order, group, desc

2. NULL vs NOT NULL

  • 尽量设为 NOT NULL,避免索引失效、存储开销增加
  • 无值用默认值(如 '', 0, 'N/A'

3. 大字段分离

  • TEXT / BLOB 字段单独建扩展表,避免影响主表查询性能

4. 软删除代替物理删除

sql 复制代码
is_deleted TINYINT DEFAULT 0 COMMENT '0-未删,1-已删'

八、规范建表示例

sql 复制代码
CREATE TABLE user (
  `id` BIGINT(16) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `user_id` BIGINT(16) NOT NULL COMMENT '业务唯一ID',
  `username` VARCHAR(45) NOT NULL COMMENT '真实姓名',
  `email` VARCHAR(100) NOT NULL COMMENT '邮箱',
  `nickname` VARCHAR(45) NOT NULL COMMENT '昵称',
  `avatar_url` VARCHAR(255) NOT NULL COMMENT '头像URL',
  `birthday` DATE NOT NULL COMMENT '生日',
  `sex` TINYINT NOT NULL DEFAULT 0 COMMENT '性别:0未知,1男,2女',
  `intro` VARCHAR(150) DEFAULT '' COMMENT '个人简介',
  `resume_url` VARCHAR(255) NOT NULL COMMENT '简历地址',
  `register_ip` INT UNSIGNED NOT NULL COMMENT '注册IP(整数)',
  `create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `review_status` TINYINT NOT NULL DEFAULT 1 COMMENT '审核状态:1通过,2审核中,3未通过,4未提交',
  `is_deleted` TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除:0-正常,1-删除',
  
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_user_id` (`user_id`),
  KEY `idx_create_time_status` (`create_time`, `review_status`),
  KEY `idx_nickname` (`nickname`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户基本信息表';
相关推荐
小陈工32 分钟前
Python Web开发入门(十七):Vue.js与Python后端集成——让前后端真正“握手言和“
开发语言·前端·javascript·数据库·vue.js·人工智能·python
0xDevNull5 小时前
MySQL数据冷热分离详解
后端·mysql
科技小花5 小时前
数据治理平台架构演进观察:AI原生设计如何重构企业数据管理范式
数据库·重构·架构·数据治理·ai-native·ai原生
一江寒逸5 小时前
零基础从入门到精通MySQL(中篇):进阶篇——吃透多表查询、事务核心与高级特性,搞定复杂业务SQL
数据库·sql·mysql
D4c-lovetrain5 小时前
linux个人心得22 (mysql)
数据库·mysql
阿里小阿希6 小时前
CentOS7 PostgreSQL 9.2 升级到 15 完整教程
数据库·postgresql
荒川之神6 小时前
Oracle 数据仓库雪花模型设计(完整实战方案)
数据库·数据仓库·oracle
做个文艺程序员6 小时前
MySQL安全加固十大硬核操作
数据库·mysql·安全
不吃香菜学java6 小时前
Redis简单应用
数据库·spring boot·tomcat·maven
一个天蝎座 白勺 程序猿6 小时前
Apache IoTDB(15):IoTDB查询写回(INTO子句)深度解析——从语法到实战的ETL全链路指南
数据库·apache·etl·iotdb