`
jaesonchen
  • 浏览: 313469 次
  • 来自: ...
社区版块
存档分类
最新评论

浅谈数据库主键策略

 
阅读更多

数据库表的主键很多童鞋都非常熟悉了,主键就是Primary Key,简称PK。

数据库主键的作用是唯一标识一条记录,所以在同一张表中,任意一条记录的主键都是唯一的,不然,数据库系统就无法根据主键直接定位记录。

虽然数据库系统本身对主键没有特别的要求,但是,写程序的时候,要考虑清楚使用什么类型的主键。正确地使用主键是存储数据成功的一半,错误地使用主键会让一个应用逐渐走向崩溃。

主键不可修改

对于数据库来说,主键其实是可以修改的,只要不和其他主键冲突就可以。但是,对于应用来说,如果一条记录要修改主键,那就会出大问题。

因为主键的第二个作用是让其他表的外键引用自己,从而实现关系结构。一旦某个表的主键发生了变化,就会导致所有引用了该表的数据必须全部修改外键。很多Web应用的数据库并不是强约束(仅仅引用主键但并没有设置外键约束),修改主键会导致数据完整性直接被破坏。

业务字段不可用于主键

所有涉及到业务的字段,无论它看上去是否唯一,都决不能用作主键。例如,用户表的Email字段是唯一的,但是,如果用它作主键,就会导致其他表到处引用Email字段,从而泄露用户信息。

此外,修改Email实际上是一个业务操作,这个操作就直接违反了上一条原则。

那么,主键应该使用哪个字段呢?

主键必须使用单独的,完全没有业务含义的字段,也就是主键本身除了唯一标识和不可修改这两个责任外,主键没有任何业务含义。

类似的,看上去唯一的用户名、身份证号等,也不能用作主键。对这些唯一字段,应该加上unique索引约束。

主键应该用什么类型

主键应该使用整数还是字符串?(用浮点数的请自觉充值智商)

我强烈建议使用字符串。

为什么?

我们先看使用整数的问题。

使用整数有两个选择:数据库自增和自己生成。

自己生成其实也是自增,无非就是把上次使用的值保存到某个地方,下次使用的时候继续自增。常见的做法是用一个单独的表存储上次用的最大值。这种方式实现复杂,可靠性低,还不如数据库自增。

数据库自增最大的问题还不在于数据库单点造成无法水平切分,因为绝大部分公司还撑不到业务需要分库的情况就倒闭了。

自增主键最大的问题是把公司业务的关键运营数据完全暴露给了竞争对手和VC。举个例子,用户表采用自增主键,只需要每周一早上去注册一个用户,把上周注册的ID和本周注册的ID一比,立刻就知道了该公司一周的新增用户数量。如果网站声称新增了10万用户,但ID却只增加了1千,就只能呵呵了。

因为主键的本质是保证唯一记录,并不要求主键是连续的。实际上不连续的更好,这样既避免了运营数据泄露,也给黑客预测ID制造了障碍,具有更高的安全性。

用字符串主键就不存在这个问题。如果我们用一个UUID作为主键,即varchar(32),除了占用的存储空间较多外,字符串主键具有不可预测性。

有人觉得UUID完全随机,主键本身没有按时间递增,不利于直接主键排序。其实解决这个问题很简单。

方法一,直接用时间戳+UUID构造一个主键,时间戳注意补0,这样生成的主键就是按时间排序的。这个方法简单粗暴,缺点是主键更长了。

方法二,自定义一个算法,时间戳放高位,序列号放低位,还可以保留机器位,然后用base32编码,可以把长度控制在20个字符内。

有人会问,根据方法二,构造包含时间戳和序列号的64位整数作为主键是否可行?

理论上来说是可行的,因为时间戳0xffffffff可以表示到2100年。但是剩下的位不是ffffffff而是只有fffff,如果给机器分配ff作为标识,那么每秒只能最多生成0xfff+1=4096个主键,对一些大型应用不太够用。

为啥64位整数除掉时间戳只能用后面的fffff位呢?这是因为JavaScript的Number类型是56位精度,它能表示的最大整数是0x1fffffffffffff,而我们迟早会用REST跟JavaScript打交道,所以要把64位整数的范围限制在0x1fffffffffffff内,否则与JavaScript交互就会出错。

虽然理论上64位整数做时间戳+序列号的主键是没问题的,但是实践中是没法绕开与JavaScript交互的,综合考虑,字符串主键最可靠。

分享到:
评论

相关推荐

    浅谈数据库设计技巧经验

    为了提高查询效率,可以采用以下优化策略: - **增加层次字段**:在每个类别记录中增加一个表示层次级别的字段,便于排序和分层显示。 - **预计算路径**:在每个类别记录中增加一个字段,存储从根节点到该节点的...

    浅谈数据库设计技巧-程序员应该读的

    1. 主键选择:选择唯一且稳定的属性作为主键,如用户ID、订单号等。 2. 外键应用:用于连接不同表,实现数据关联,确保数据完整性。 3. 字段类型选择:根据数据特性选择合适的数据类型,如INT、VARCHAR、DATE等。 4....

    浅谈数据库设计技巧[pdf]

    不同类型的数据结构和应用场景需要采取不同的设计策略。通过上述讨论,我们可以看到,从基本的数据结构出发,结合实际应用需求,逐步迭代优化数据库设计方案,是成为一名优秀数据库设计师的关键。

    浅谈数据库设计技巧 关于sql

    正确选择主键和外键,以及利用聚集和非聚集索引,有助于优化数据库性能。在处理大量数据时,分区和分片策略也可以提高查询效率。 总之,数据库设计不仅要满足当前需求,还要考虑到未来扩展性和性能优化。不断学习和...

    浅谈Oracle数据库表的设计技巧.pdf

    在数据库表中,非空字段如主键、编号字段要求必须填写,以确保数据一致性。然而,一些可选字段如员工爱好、备注等允许为空。NULL字段并不存储任何内容,因此在查询时,直接用空字符可能无法找到相应记录。设计时应将...

    浅谈如何优化SQL Server数据库.pdf

    采用合理的数据库对象放置策略;优化SQL语句语法;合理使用外部工具以使SQL更加灵活和高效;以及进行清理和删除日志、备份数据库和清除垃圾数据等操作。 在数据库设计的优化方面,索引设计是一个关键因素。索引的...

    浅谈基于Oracle高级复制实现数据库同步热备.pdf

    ### 基于Oracle高级复制实现数据库同步热备的关键知识点 #### 一、基本概念解析 1. **主站点(Master Site)**:提供数据源的站点,在本例中即为ORACLE数据库站点。 2. **实体化视图站点(Materialized View Site...

    浅谈MyBatis-Plus学习之Oracle的主键Sequence设置的方法

    在Oracle数据库中,由于不支持自动递增的主键策略,开发者通常会使用Sequence来生成主键值。本文将深入探讨如何在MyBatis-Plus(MP)框架中配置Oracle的主键Sequence。 首先,Oracle Sequence是Oracle数据库提供的...

    浅谈SQL Server的查询优化.pdf

    优化查询性能主要涉及数据库设计、查询策略和物理数据库的实现等方面。 【数据库设计】良好的数据库设计是优化查询性能的基础。遵循范式设计原则可以减少数据冗余,降低数据存储所需的页面数量,但过度规范化可能...

    使用Mysql来搭建可扩展的SNS网站(浅谈)

    标题与描述:“使用Mysql来搭建可扩展的SNS网站(浅谈)” 知识点解析: 在探讨使用MySQL来搭建可扩展的社交网络服务(SNS)网站的过程中,文章重点介绍了如何利用MySQL数据库来应对SNS网站特有的数据挑战,特别是在...

    浅谈redis的maxmemory设置以及淘汰策略

    4. **allkeys-random**:随机淘汰主键空间中的键。 5. **volatile-random**:随机淘汰设置了过期时间的键。 6. **volatile-ttl**:优先淘汰具有更早过期时间的键。 选择合适的淘汰策略取决于你的业务需求。例如,...

    浅谈Mybatis通用Mapper使用方法

    浅谈Mybatis通用Mapper使用方法 Mybatis通用Mapper是Mybatis框架中的一种插件,主要用于简化数据库操作的编写。它提供了许多实用的方法,例如单表的增删改查操作等。下面将详细介绍Mybatis通用Mapper的使用方法。 ...

    SQL Server 服务器优化技巧浅谈

    这些优化策略旨在提升SQL Server的整体性能,减少潜在的瓶颈,并为数据库的稳定性和恢复能力提供保障。通过实施这些技巧,数据库管理员能够更好地管理和维护其SQL Server环境,确保系统的高效运行。

    浅谈django orm 优化

    本文旨在浅谈Django ORM的性能优化技巧,希望能够对提升Django应用的性能有所帮助。 首先,我们要意识到,任何性能优化都需要建立在对当前应用性能瓶颈的准确理解之上。性能优化并不是一种可以随意套用的模板,而应...

    浅谈MySQL 统计行数的 count

    InnoDB在执行`count(*)`时,会尝试优化,例如通过查找最小的普通索引树而非主键索引树来减少扫描的数据量。此外,`show table status`命令可以快速给出行数估计,但它依赖于索引统计,并可能存在较大的误差。 面对...

    浅谈MySQL和Lucene索引的对比分析

    总的来说,MySQL和Lucene的索引设计反映了它们在不同场景下的优化策略。MySQL侧重于事务处理和结构化数据的快速访问,而Lucene则专注于文本数据的高效搜索。了解这些差异有助于我们在实际应用中选择合适的技术,并...

    SQLite入门与分析

    在SQLite入门与分析(七)---浅谈SQLite的虚拟机.doc中,主要讲解了SQLite如何通过虚拟机执行SQL语句。SQLite的虚拟机,也称为VDBE(Virtual Database Engine),是SQLite的核心组件。它负责解析SQL语句,将其转化为一...

    浅谈MySQL分页Limit的性能问题

    对于自增主键,通常已经有索引,但如果使用其他字段进行分页,需要创建相应的索引以提升性能。 在实际应用中,可以根据数据量和分页需求动态选择优化策略。例如,对于小规模的分页,可以直接使用`LIMIT`;而对于较...

    浅谈hibernate急迫加载问题(多重外键关联)

    在Java开发中,Hibernate是一个非常流行的ORM(对象关系映射)框架,它允许开发者通过面向对象的方式操作数据库。然而,在处理复杂的数据关联时...在设计数据库和选择加载策略时,应根据实际应用需求和性能考虑来权衡。

Global site tag (gtag.js) - Google Analytics