• 首页
        • 更多产品

          客户为中心的产品管理工具

          专业的软件研发项目管理工具

          简单易用的团队知识库管理

          可量化的研发效能度量工具

          测试用例维护与计划执行

          以团队为中心的协作沟通

          研发工作流自动化工具

          账号认证与安全管理工具

          Why PingCode
          为什么选择 PingCode ?

          6000+企业信赖之选,为研发团队降本增效

        • 行业解决方案
          先进制造(即将上线)
        • 解决方案1
        • 解决方案2
  • Jira替代方案
目录

OCC和MVCC的区别是什么

最简单的并发控制算法是2PL(2 Phase Locking),分为两阶段:1)获得锁阶段;2)释放锁阶段。一般2PL被称为是悲观并发控制。与之相对的是乐观并发控制OCC( Optimistic Concurrency Control)。OCC假设事务会成功,开始事务时该读读,该写写,不加锁。

一、OCC和MVCC的区别

最简单的并发控制算法是2PL(2 Phase Locking),分为两阶段:

1)获得锁阶段;

2)释放锁阶段。

一般2PL被称为是悲观并发控制。

与之相对的是乐观并发控制OCC( Optimistic Concurrency Control)。OCC假设事务会成功,开始事务时该读读,该写写,不加锁。只有到提交时做一下验证,验证这个事务是不是能够成功提交。 OCC分为三阶段:

1)Read Phase, 对于读,放到Read Set,对于写,把写记到临时副本,放到Write Set。因为写是写到临时区的,属于未提交结果,其它事务读不到(这点是和MVCC的重要区别);

2)Validation Phase,重扫Read Set,Write Set,检验数据是否满足Isolation Level,如果满足则Commit,否则Abort;

3)WritePhase,或者叫做Commit Phase,把临时副本区的数据更新到数据库中,完成事务提交。

MVCC(Multiversion Concurrency Control)是另一种并发控制算法。MVCC为每条记录维护多个快照(Snapshot),通过起止两个时间戳(Begin Timestamp / End Timestamp)维护副本的可见性。读写进行的不同操作如下:

Update,创建一个新的版本(Version);

Delete,更新End Timestamp。

Read,通过起止时间戳判定记录是否对当前事务可见(OCC读不到未提交的记录,所以不需要做这个判断)。

这样,通过Snapshot,实现了读写互不阻塞。但为了实现Serializable,对读写规则还是要进行一定的限制。MVCC通过不同的方法实现。有基于锁定的,MV-2PL,如MySQL。有基于时间排序(Time Ordering)的,叫MV-TO,如PostgreSQL。其实准确来说,PG的实现叫SSI(Serializable Snapshot Isolation),不算MV-TO。也有像OCC那样基于乐观算法的,MV-OCC,即读写时不做验证,延迟到提交时验证。

效率上,2PL读写阻塞,在维护锁开销较小时较好;OCC不维护锁,一些比较新的OCC算法吞吐可以做得很高,不过相应回滚也会比较高,冲突比较小和验证开销小时比较好;MVCC对不同类型的workload都有很好的适应性,读写互不阻塞,回滚率也比OCC好,很多RDBMS也都用MVCC,如Oracle,PostgreSQL,MySQL。还有一个效率问题,随着现在CPU核心数越来越多,考虑并发控制算法往往需要考虑它的多核扩展性好不好。由于多数MVCC,OCC算法都需要时间戳分配,时间戳通常对全局变量进行CAS(Compare And Swap)操作来计算,当核心数变大时,CAS的争用也变大了。

另外,现在的许多并发控制方法经常混合了多种算法。先有人提出了A,后有人提出了B,再后来就有人提出了A+B,那么A+B应该是叫A呢还是叫B呢?就像上面提到的MV-2PL,MV-TO,MV-OCC。

延伸阅读:

二、id的一些典型的类型

  • 整型:整型通常来说是优异的选择,这是因为整型的运算和比较都很快,而且还可以设置 AUTO_INCREMENT 属性自动递增。
  • ENUM 和 SET:通常不会选择枚举和集合作为 id,然后对于那些包含有“类型”、“状态”、“性别”这类型的列来说是挺合适的。例如我们需要有一张表存储下拉菜单时,通常会有一个值和一个名称,这个时候值使用枚举作为主键也是可以的。
  • 字符串:尽可能地避免使用字符串作为 id,一是字符串占据的空间更大,二是通常会比整型慢。选用字符串作为 id 时,还需要特别注意 MD5、SHA1和 UUID 这些函数。每个值是在很大范围的随机值,没有次序,这会导致插入和查询更慢:
  • 插入的时候,由于建立索引是随机位置(会导致分页、随机磁盘访问和聚集索引碎片),会降低插入速度。
  • 查询的时候,相邻的数据行在磁盘或内存上上可能跨度很大,也会导致速度更慢。

如果确实要使用 UUID 值,应当移除掉“-”字符,或者是使用 UNHEX 函数将其转换为16字节数字,并使用 BINARY(16)存储。然后可以使用 HEX 函数以十六进制的方式进行获取。UUID 产生的方法有很多,有些是随机分布的,有些是有序的,但是即便是有序的性能也不如整型。

相关文章