mysql 不建议定义主键是为什么
时间: 2023-11-14 14:05:06 浏览: 121
MySQL并不是不建议定义主键,相反,它是强烈建议定义主键的。但是有时候在某些特定情况下,可能会存在一些特殊的情况,导致在某些表中不定义主键可能更加合适。
一般来说,建议在每个表中都定义主键。主键可以帮助我们唯一标识一条记录,而且MySQL会在主键上自动创建索引,可以提高查询速度和数据的完整性。同时,主键还可以用于进行表之间的关联。
但是,在某些情况下可能不需要定义主键,比如一些临时性的表或者数据量非常小的表,这样可以减少一些额外的开销。但是这种情况应该是非常少见的,大部分情况下还是应该定义主键。
相关问题
mysql 时间序列主键
### MySQL 中实现时间序列作为主键
在MySQL中,可以利用`TIMESTAMP`或`DATETIME`类型的字段来创建基于时间戳的时间序列主键。为了确保该字段能够唯一标识每条记录并遵循良好的设计实践,通常会结合其他机制一起使用。
#### 方法一:组合时间戳与其他唯一标识符
一种常见的方式是将当前时间戳与另一个能保证唯一的部分相结合形成复合主键。例如:
```sql
CREATE TABLE example_table (
ts DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
unique_part VARCHAR(36) NOT NULL,
PRIMARY KEY (ts, unique_part)
);
```
这里采用了精度达到微秒级别的 `DATETIME(6)` 类型[^1],并且定义了一个辅助列用于增强唯一性。对于 `unique_part` 可以考虑采用UUID或其他业务层面可区分的信息填充。
#### 方法二:自动生成带有前缀的时间戳字符串
另一种思路是在应用层生成包含特定格式化日期/时间信息在内的字符串形式的主键值,在插入之前先计算好完整的ID再传入数据库。比如下面这个例子展示了如何构建形如 "YYYYMMDDHHMISS-随机数" 的主键值:
```sql
SET @prefix = DATE_FORMAT(NOW(),'%Y%m%d%H%i%s');
INSERT INTO another_example(id,value) VALUES(CONCAT(@prefix,FLOOR(RAND() * 90000 + 10000)),'some value');
```
这种方法虽然简单易懂,但在高并发环境下可能会遇到重复的风险,因此建议配合锁或者其他同步措施加以保护[^2]。
#### 方法三:借助触发器和存储过程动态分配带有序号的时间戳
更复杂但也更为可靠的做法是通过编写触发器或者调用存储过程来自动生成具有连续序号特征的时间序列主键。这涉及到额外维护一张专门用来跟踪各时间段内已发放的最大编号的小表,并据此派生新的主键值。具体操作如下所示:
首先建立一个追踪最大序数值的小表:
```sql
CREATE TABLE seq_tracker(
datepart DATE NOT NULL PRIMARY KEY,
max_seq INT UNSIGNED NOT NULL DEFAULT 0
);
```
接着为实际的目标表设定结构:
```sql
CREATE TABLE target_with_timestamp_id(
id CHAR(20), -- 假设长度足够容纳最长可能的结果串
content TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY(id)
);
```
最后提供一段负责生产新id的函数以及相应的before insert trigger:
```sql
DELIMITER $$
CREATE FUNCTION generate_time_based_id()
RETURNS CHAR(20)
BEGIN
DECLARE newId CHAR(20);
DECLARE curDatePart DATE;
DECLARE nextSeqNo INT;
SELECT CURDATE() INTO curDatePart ;
LOCK TABLES seq_tracker WRITE ;
IF EXISTS(SELECT * FROM seq_tracker WHERE datepart=curDatePart ) THEN
UPDATE seq_tracker SET max_seq=max_seq+1 WHERE datepart=curDatePart ;
ELSE
INSERT INTO seq_tracker(datepart,max_seq)VALUES(curDatePart ,1);
END IF;
SELECT CONCAT(DATE_FORMAT(CURDATE(),"%Y%m%d"),LPAD(max_seq,8,"0")) AS generated_id
INTO newId FROM seq_tracker WHERE datepart=curDatePart LIMIT 1;
UNLOCK TABLES;
RETURN newId;
END$$
DELIMITER ;
DROP TRIGGER IF EXISTS before_target_insert;
CREATE TRIGGER before_target_insert BEFORE INSERT ON target_with_timestamp_id FOR EACH ROW BEGIN
SET NEW.id = generate_time_based_id();
END;
```
上述代码片段实现了每天重置计数的基础之上按顺序递增的功能,从而使得最终形成的主键既包含了当天的具体时刻又具备全局范围内的唯一性质[^3]。
mysql用uuid主键
### 使用 UUID 作为主键的最佳实践
在 MySQL 数据库中使用 UUID 作为主键具有独特的优势,尤其是在分布式环境中。然而,在实现过程中需要注意一些细节以确保最佳性能。
#### 创建表结构
当创建带有 UUID 主键的表格时,建议定义 `CHAR(36)` 类型列并设置为 `NOT NULL` 和 `UNIQUE` 属性。为了简化操作流程,可以通过默认值的方式自动生成新的 UUID 值[^2]:
```sql
CREATE TABLE users (
user_uuid CHAR(36) PRIMARY KEY DEFAULT (UUID()),
username VARCHAR(50),
email VARCHAR(100)
);
```
上述 SQL 语句会建立一张名为 `users` 的表,其中 `user_uuid` 字段将自动填充由 `UUID()` 函数产生的唯一标识符。
#### 插入数据
向包含 UUID 主键的表内插入记录非常简单,只需省略该字段即可让其自行生成:
```sql
INSERT INTO users(username, email) VALUES ('john_doe', 'john@example.com');
```
执行这条命令之后,系统将会为新加入的数据行分配独一无二的 `user_uuid` 值。
#### 查询优化
尽管 UUID 提供了全局唯一性的优势,但由于其长度较长且随机分布特性可能导致索引效率降低。因此对于高并发读取场景下的应用来说,可能还需要考虑其他因素来平衡查询速度与存储成本之间的关系[^1]。
#### 处理特殊字符
由于标准格式下生成的 UUID 含有连字符 `-` ,这可能会引起与其他系统的兼容性问题。为了避免这种情况发生,可以在保存之前利用 `REPLACE` 函数移除这些不必要的符号[^4]:
```sql
SET @raw_uuid = UUID();
UPDATE some_table SET uuid_field=REPLACE(@raw_uuid,'-','');
```
以上代码片段展示了如何先获取原始形式的 UUID 并将其转换成无分隔线版本再更新到指定字段之中。
阅读全文
相关推荐
















