当前位置: 首页 > 科技观察

数据库如何获取和处理数据

时间:2023-03-16 18:16:57 科技观察

SQL是StructuredQueryLanguage(结构化查询语言)的缩写。用户只需要通过SQL告诉数据库自己需要什么。至于怎么做,是数据库管理系统(DBMS)需要考虑的问题。上一篇《SQL语句处理》介绍了数据库执行的四个阶段,以及每个阶段做了哪些工作。今天的文章继续讨论数据库是如何获取用户需要的数据的。下面讨论的内容只适用于Oracle单机环境,RAC环境略有不同,不在本文讨论范围之内。数据库的所有增删改查操作都在内存中完成。数据库为了处理数据,首先需要将数据从磁盘读入内存,然后进行相应的操作。但是内存和磁盘的读写速度差别很大。DDR4内存的读写速度约为每秒50G(50000M),固态硬盘的速度为每秒300M,是内存的二百分之一,机械硬盘的速度为100M每秒,这是内存的五分之一。为了解决两者速度差异的问题,诞生了缓存的概念。缓存的作用是避免每次获取数据都从慢盘读取,而是将之前访问过的数据缓存在内存中。如果后续操作需要相同的数据,可以直接从内存中获取,大大提高了读取速度。Oracle内存结构中有一个非常重要的结构叫做DBBufferCache。DBBufferCache位于SGA中。在正常的系统中,这部分内存占了整个Oracle内存结构的大部分。如果DBBufferCache很大,几十G,甚至几百G,每次查找需要的block是否存在都需要很长时间。因此,Oracle为了提高效率,将DBBufferCache划分为多个区域,每个区域称为工作集(workset),每个工作集又划分为多个哈希桶,一个哈希桶管理一个或多个数据块。为了保证数据的一致性,对哈希桶的访问是串行的,并受到相应的锁存器的保护。只有获得相应闩锁的会话才能在哈希桶上搜索数据块。1、查询语句的执行假设如下查询语句:SELECT*FROMemployeesWHEREemployee_id=199;表employees的结构如下,employee_id是表的主键。先看上面SQL语句的执行计划。首先根据索引EMP_EMP_ID_PK查找employee_id=199这个key,得到key对应的valueROWID。ROWID指向数据块的真实地址。通过ROWID获取数据块。获取数据块后,从数据块中获取符合条件的数据。在这个过程中,至少需要访问两个数据块(为了简化过程,忽略其他数据块),一个是key为199的索引块,假设为块100;另一个是索引块指向的数据块,假定为1000号块。在前面的缓存介绍中提到过,为了提高数据的访问速度,Oracle会将访问过的数据块缓存在DBBuffer缓存中,以供重用。因此,在获取上述索引块100时,需要先检查索引块100是否已经存在于DBBuffercache中,以减少昂贵的磁盘读取。在搜索DBBuffercache之前,必须先获取对应的latch再进行搜索。如果没有拿到latch,此时会进入等待状态。拿到latch后,就可以搜索DBBuffer缓存了。如果内存中已经存在索引块100,并且没有会话在修改数据块的内容,则直接访问内存中的数据块,获取key为199的数据。如果有会话在修改这个数据块的内容,需要通过undo数据和当前数据块构造一致的读版本数据块来读取session修改前的历史版本数据。如果100号索引块不在内存中,首先判断是否有其他会话将100号索引块读入内存,如果有则等待。否则,通知后台进程从磁盘中读取100号索引块到内存中。在将100号索引块读入内存之前,需要在内存中找到一个合适的空闲块来保存要读取的100号索引块。查找空闲块时也需要获取latch。如果内存中没有空闲空间,则通知后台刷新进程刷新脏页以腾出空闲空间。如果内存有空闲空间,直接将100号索引块读入内存。获取ROWID后,再次读取数据块。读取数据块的过程与读取索引块的过程相同。读取数据块后,从数据块中获取符合条件的行返回给客户端。2.DML语句执行假定以下更新语句:UPDATEemployeesSETfirst_name='Hello',last_name='Kitty'WHEREemployee_id=199;更新语句的执行计划如下:DML语句都有相应的查询过程,因为只有查询找到所有需要修改的数据,才能进行相应的操作。查询过程与查询语句执行过程大致相同。但也有以下区别:在获取latch时,如果是只读操作,多个session可以同时获取同一个latch,如果是DML操作,则不能同时获取.对于只读操作,多个会话可以同时读取同一个数据块,而DML操作不能为多个会话同时修改同一个数据块。获取到数据块后,进行相应的操作,记录相应的undo信息和redolog信息,完成更新操作。