我们需要考虑以下两个核心点:
1.数据组织:
我们怎样在内存/页中布局我们的数据结构?我们应该存储哪些信息来支持高效查询呢?
2.并发:
我们怎样允许多个线程访问数据库而不造成问题呢?

Hash 概述

在这种模型下, 数据库使用Hash Table 来保存Tuple

而Hash Table 通常包括两部分:Hash 函数和Hash Scheme

Hash Scheme是当我们在我们的hash table中遇到hash碰撞时,我们处理问题的机制或步骤。
Hash函数可以接受进行任意类型的输入,并返回一个固定长度的(32位或64位)的整形值。hash函数有很多种,而数据库系统比较关注函数的速度和碰撞率。它的速度应尽可能的快,碰撞率应尽可能的低。至于安全性,数据库系统会对数据进行加密,但是对数据的hash索引并没有加密的必要性。

我们比较常见的hash函数有 sha-256, md5等等,但是这两个由于考虑了安全性,所以效率比较低。数据库常用的hash函数有以下几种:

我们使用hash算法得到的slot内存放的不一定就是这个key- value键值对,而可能是一个指针,指向存放有key- value对的空间。

几种常见的hash scheme实现

静态hash scheme

静态意味着当我们分配内存的时候,我们一开始就得知道我们希望保存的key的数量。否则,如果容量满了或者需要缩减,需要重新建表操作,这意味着我们需要重构hash table

1.Linear Probe Hashing

2.Robin Hood Hashing

3.CuckooHashing

动态hash scheme

动态hash scheme 能够在无须重建整个东西的情况下,根据需要调整大小

1.Chain Hashing

2.Extendible Hashing

3.Linear Hashing

值得注意的是,在我们的实际应用中,很少使用Hash作为我们存储页的方式的。因为他虽然插入,单个查询很简单,但是一旦我们要用到范围查询时,就会变的很麻烦。

Table Index

表索引是表中子集的副本,这些副本被组织和排序,以便更高效的得到数据库中的某些数据。这意味着,当我们对数据库表更新时,对索引的更新也应该是同步的

B树和B+树的区别

B+树的key对应的值(record id或者具体的tuple)只会保存在叶子结点中,而B树则也会保存在inner node中。这意味着B+树的key会出现多次:既在叶子结点中出现,也在非叶子结点中作为路标出现。其次,当我们删除B+树中的某个节点的时候,我们会在叶子结点中将其删除,但我们却并不一定在非叶子结点中删除它(这取决于我们是否要重新平衡)。这样看来B树似乎更加经济,节省空间,因为它不会对key进行复制。然而在实际的系统中没有人使用B树的原因在于,多线程操作B树的时候,代价过于昂贵。我们删除或修改非叶子结点的值的时候,可能会将节点上下移动,这需要我们进行加锁操作来保证线程安全。

优化B+树

1.磁盘的访问速度越慢,page的值应当设计的越大。
我们可以将树的每个节点当作一个page。 如果数据库使用的硬盘的访问速度很慢,那么在构建树的索引的时候,我们倾向于使用更大的节点。因为如果使用小节点,那么我们由于一次顺序访问(访问一个页)得到的数据量有限,就需要不断的进行寻址,在页之间跳转,那么由于IO速度慢,这将耗费大量时间,因此我们可以让一次寻址读取到的数据量大一些。

通常情况下,
机械硬盘:一个页1MB
固态硬盘:一个页10KB
内存:一个页512KB

2.当我们由于节点的删除使得节点中key的个数半满的时候,我们按照B+树的规则需要对其进行节点间的合并操作以使得树结构平衡。但是实际操作中我们不必每次都这样做,我们可以使树暂时不平衡,然后在某一段时间内重构树使其重新平衡,这样就不必浪费过多时间在树的节点合并上。

3.当我们的key的长度不确定的时候,我们如何在一个树节点中存储多个这样不确定长度的key-value对

第一种方法是,我们不存储这种不确定长度的key,而是存储record id,我们要对key进行对比的时候,直接根据record id,找到该record id指向的tuple,再拿出tuple的key与之进行对比。毫无疑问,这样速度将会非常慢,但它节省了内存空间,因为我们要存储的只是固定长度的record id。在内存型数据库中曾经使用过这种方法,但现在基本没人使用
第二种方法是,我们使用不同大小的node来保存一个个key-value对。这样毫无疑问会面临数据存储方式的问题,因为我们的buffer pool和内存更希望我们使用同样大小的页来存储数据以方便进行页的换入换出。
第三种方法是,使用padding,直接强行让每个node都适应最大长度的那个key,而这会浪费空间
第四种方法是使用 sorted key map
定义一个排序数组,数组的每个元素是一个key以及该key的实际偏移量(类似于前面讲过的slot array),因此它可以指向key- value对应的位置

4.前缀压缩

我们无须将相同的前缀一次又一次的保存在node中,而是只保存一次,这大大的节省了空间。
5.后缀截断
当我们仅仅可以根据key的前面几个字母就可以决定向左或者向右查找的时候,我们无需再保存key后面的内容。

6.自下而上的构建索引
当我们有了大批的已知数据集,想要对其进行索引构建的时候,我们无须从上而下逐个插入树中,而是先对数据进行排序,然后取中间值构成父节点


索引值相同的情况下的处理办法

1.修改索引:使用另外一个额外的,独一无二的属性列(比如 record id),与有重复属性的这一列形成组合索引,这样可以使索引独一无二

2.修改B+树:
1.将每一个重复的key都正常存入B+树中,这样做会使得查询效率下降,因为可能好多节点上都key都相同,此外,由于有大量重复key,会使得空间利用率降低。但这样做都好处是比较简单,容易实现
2.在key下面增加一个bucket,将相同的key对应都不同值存入bucket中。这样做需要修改B+树叶子节点的代码,因为这样一来每一个节点的大小都不一样,并且bucket的增长会使得其最终超过叶子节点所可以容纳的,这样就要在另一个block上存了,而这又会引起额外的IO。不过这样做的好处是没有造成空间上的浪费。
这两种方法都有相同的缺点:对于key的删除将会变得很低效,为了解决 这种低效可以采用修改索引的办法。由于删除效率低下,以及重复搜索键导致的其他复杂功能,大多数数据库系统中的B+树实现仅处理唯一的搜索键,并自动添加记录ID或其他属性,使非唯一搜索键独一无二。

多线程访问索引

我们前面讨论的数据结构实际上都是在单线程下运行的。但实际上,我们的数据库系统是会有多个线程去同时访问的,这会造成数据库系统的线程安全问题,因此,我们必须去考虑多线程访问索引的不同情况。
1.Lock和Latch的区别
Lock保护的是数据库逻辑的正确性,在事务执行阶段被持有,需要考虑事务回滚。而Latch保护的是数据库内部数据结构的正确性,在操作(增删改查)执行的时候被持有,并且不需要考虑是否回滚。在操作系统世界中,Latch实际上就是lock或者mutex。只不过在数据库系统中为了与我们事务上的Lock区分开,所以我们称之为Latch。

两种不同种类的Latch

2.Latch的两种实现方式
1.使用语言内置的mutex
这实际上对应于操作系统的futex.
futex: a sort of fast, user-space mutual exclusion primitive.
Futex是一种用户态和内核态混合的同步机制。首先,同步的进程间通过mmap共享一段内存,futex变量就位于这段共享的内存中且操作是原子的,当进程尝试进入互斥区或者退出互斥区的时候,先去查看共享内存中的futex变量,如果没有竞争发生,则只修改futex,而不用再执行系统调用了。当通过访问futex变量告诉进程有竞争发生,则还是得执行系统调用去完成相应的处理(wait 或者 wake up)。简单的说,futex就是通过在用户态的检查,(motivation)如果了解到没有竞争就不用陷入内核了,大大提高了low-contention时候的效率。
2.使用自己定义的cas操作
在现代CPU中就有cas原子指令

3.支持索引结构并发访问的实现依据:所有的访问都是一个方向的:对于B+树,都是从根节点到叶子结点,而对于hash table,都是线性探测的方向。这样就保证了不会造成死锁
4.latch的不同粒度
在hash索引上,latch的粒度分为page和slot

page粒度会在整个page上加写锁或者读锁,而slot粒度则只会在访问每个slot时加锁,后者会提高并发性能。

B+树索引的加锁
当我们在B+树上有多个进程同时更改node时,会引发以下问题:我们对node的操作很有可能导致其会发生合并或分裂,而发生合并或分裂之前,如果我们当前线程被调度出去,其他线程执行查找操作,在查找到当前节点时,线程又进行了调度导致该节点被分裂或者合并。这样会使得其他线程对该node节点的操作出现问题。
解决这个问题的方案被称为:latch coupling

如果当前对于该节点的操作是安全的,我们释放掉之前积累的锁,而如果对当前节点的操作是不安全的,我们持续对节点加锁直到到达某个安全点,才会对之前的锁全部释放掉。
对于安全的定义:在当前节点进行插入或者删除(这取决于你正在进行的动作)不会使得该节点发生分裂或合并。

但是这样的操作会导致性能过低:我们锁了太多的节点。

解决办法是采用一种乐观的思维:即我们的操作一般不会使得节点发生分裂或合并。因此,我们对于节点加的锁不应是写锁,而是读锁。当我们到达叶子节点并操作时,如果不会发生分裂或合并,就万事大吉。而如果会发生,说明我们的操作是不安全的,因此我们重新走流程,加上写锁。

5.对叶子节点的双向链表扫描时出现死锁的问题
由于我们之前的操作方向都是一致的,而对于双向链表的扫描可能会出现方向冲突从而导致死锁。对于该问题的解决方案是:放弃争夺,重新开始操作。

Database---Access Methods相关推荐

  1. Zabbix篇之Web登录页面报错:Database:Error connecting to database: Access denied for user ‘zabbix‘ @ ‘localhos

    一.前言 当搭建好了Zabbix监控服务后,访问Web页面时,通常会进行相关的配置信息登录. web页面的访问,可在浏览器中输入:http://IP地址:端口号/zabbix, 当在进行到该步骤时,通 ...

  2. C# 操作 Database(Access SQL)

    操作数据库步骤: 建议使用using块 1)连接到数据库, a)创建连接字符串 b)创建连接对象 c)连接打开 2) 执行增.删.改.查, a)创建命令文本 b)创建命令对象 c)执行命令返回结果到D ...

  3. Interview QA-COBOL COBOL II

    Q1) Name the divisions in a COBOL program ?. A1) IDENTIFICATION DIVISION, ENVIRONMENT DIVISION, DATA ...

  4. mysql越权漏洞_Fortify漏洞之Access Control: Database(数据越权)(示例代码)

    继续对Fortify的漏洞进行总结,本篇主要针对 Access Control: Database(数据越权)的漏洞进行总结,如下: 1.Access Control: Database(数据越权) ...

  5. 如果有人问你关系数据库的工作原理,叫他看这篇文章How does a relational database work

    When it comes to relational databases, I can't help thinking that something is missing. They're used ...

  6. How does a relational database work

    How does a relational database work NOSQL跟SQL一样,在内存中都是用hash table,都是key-value 只不多nosql几乎无锁,无事务,速度更快, ...

  7. [翻译]The Data Access Application Block

    Enterprise Library 4.1 - October 2008 The Data Access Application Block 数据访问应用块 The Enterprise Libra ...

  8. 计算机网络access code,access code

    Before moving on to the Ad controller, you might have noticed that the controller methods make direc ...

  9. 【数据库】数据库管理系统(Database Management Systems)

    数据库管理系统(Database Management Systems) 数据库管理系统是一种操纵和管理数据库的大型软件,用于建立.使用和维护数据库,简称 DBMS.它对数据库进行统一的管理和控制,以 ...

  10. Oracle IMS DB2都属于,IMS数据库  IMS database

    摘 要: IMS(Information Management System)是一种层次型的数据库管理系统,其数据以一种树型的逻辑拓扑结构进行存储,非常适合支持高可用性.高性能.高容量.低成本的关键性 ...

最新文章

  1. 为什么执行自己的程序要在前面加./
  2. samtools 检测bam文件的完整度
  3. Java从入门到精通——数据库篇之JAVA中的对Oracle数据库操作
  4. 【最全最详细】publiccms常用的代码片段
  5. 漫画:五分钟看懂车联网
  6. java无序数组_Java查找不重复无序数组中是否存在两个数字的和为某个值
  7. js获取精确宽度/高度(带小数位像素)
  8. python批量复制粘贴_用python批量复制特定图片
  9. 自己动手实现一个简单的 IOC,牛皮!!
  10. Exchange Server 2013安装部署初体验
  11. 未来瓶窑的交通生命线与发展规划
  12. 游戏启动流程的逆向分析与多开的实现
  13. STM32 freertos堆栈溢出检查方法
  14. 历数OpenMobile开发的一些坑
  15. JAVA组合框怎么添加加减乘除,[C#]组合框设计windows加减乘除简单计算器应用
  16. 悟空qq通讯录加好友
  17. 好的工具分享(持续更新)
  18. python多项式拟合:np.polyfit 和 np.polyld
  19. Linux几种包下载安装方式
  20. 面对海量资产运维的行云管家应对之道

热门文章

  1. 计算机体系结构——动态流水线动态调度详解
  2. 30秒集结会议、能开“会中会” IMO班聊助力高效协同办公
  3. 数据结构--三角矩阵的压缩存储
  4. cyk的小学数学题 小学数学
  5. 今日金融词汇---股票回购,是什么意思?
  6. react 电话344格式
  7. 神经网络一般架构(BP)
  8. RRT(Rapidly-Exploring Random Trees)算法详解及python实现
  9. SBI集团向“Smart Card”钱包制造商投资1500万美元
  10. Java项目运维与监控调优