数据库:缓冲池和磁盘I/O
关系型DBMS最重要的一个目标是确保表或者索引中的数据时随时可用的。为了尽可能实现这个目标,使用缓冲池来最小化磁盘活动。每个DBMS会根据对象类型(表或索引)及页的大小拥有多个缓冲池,每个缓冲池都足够大,可以存放许多页。
缓冲池管理器将尽力确保经常使用的数据保存在池中,以避免一些不必要的磁盘读。索引或表页在或不在缓冲池中,访问的成本是不同的。
从缓冲池进行的读取
如果一个索引或者表页在缓冲池中被找到,那么唯一的成本就是去处理这些索引或者表的记录。
从磁盘驱动器进行的随机I/O
一个页包含了多条记录,我们可能需要页上所有行,或者其中部分行,又或者是其中某一行,但所花费的时间是相同的,约10ms。如果磁盘被重度使用,这一速度也将大幅降低,因为需要等待磁盘空闲下来。
10ms是怎么得来的?假设有6ms是磁盘的实际繁忙时间,将页从磁盘服务器缓冲区移至数据库缓冲池花费1ms,剩余3ms是对于可能发生的排队时间的估算值。这些数字在实际情况中都可能有变化,但只需要记住10ms这一粗略但合理的数字即可。
从磁盘服务器缓存进行的读取
现今的磁盘服务器都提供自己的内存(或缓冲区)以降低响应时间上的巨大成本。就像从数据库缓冲池读取一样,磁盘服务器会将频繁访使用的数据保留在内存(缓冲区)中,以降低高昂的磁盘读成本。
从磁盘驱动器进行的顺序读取
在实际场景下,我们需要将多个页读取到缓冲池中,并按顺序处理他们。DBMS会意识到多个索引或表页需要被顺序的读取,且能识别出那些不在缓冲池的页。随后,它将发出多页I/O请求,每次请求的页的数量由DBMS决定。
顺序的读取页有两个非常重要的优势:
(1)同时读取多个页意味着平均读取每个页的时间将会减少,约0.1ms每页。
(2)由于DBMS事先知道需要读取哪些页,所以可以在页被真正请求之前就提前将其读取进来,我们称其为预读。
辅助式随机读
除了缓冲池和磁盘缓冲区可以降低随机读取的成本以外,还有其他一些场景也能降低这一成本,有时是自然发生的,有时是优化器有意为之的,我们把它们统称为辅助式随机读。
自动跳跃式顺序读
如果一系列不连续的行被按照同一方向扫描,那么访问模式将会是跳跃式顺序的。于是,每行的平均I/O时间自然就比随机访问时间短,跳跃的距离越短则节省的时间越多。跳跃式顺序读的好处能够在两种情况下被放大:
(1)磁盘服务器可能注意到对某一驱动器的访问时顺序的(或者几乎时顺序的),于是服务器开始向前提前读取多个页。
(2)DBMS可能注意到SELECT语句正以顺序的或者几乎顺序的方式访问索引或表页,于是DBMS便开始向前提前读取多个页。
列表预读
当表行和索引行访问的顺序不一致时,DB2 for z/OS能够先访问所有满足条件的索引行,然后按照表页的顺序对索引行进行排序后再访问表行。
数据块预读
当表行和索引行的访问顺序不一致时,Oracle会使用数据块预读这一特性。DBMS先从索引片上搜集指针,然后再通过多重随机I/O来并行地读取表行。
辅助式顺序读
当要扫描一张大表时,优化器可能会开启并行机制。例如,它可能会将一个游标拆分为多个用范围谓词限定的游标,每一个游标扫描一个索引片。当有多个处理器和磁盘驱动器可用时,所花费的时间将相应减少。
同步I/O和异步I/O
术语同步I/O是指再进行I/O操作时,DBMS不能进行其他操作,它必须等待,直至I/O操作完成。
异步I/O是指当上一步的页尚在处理时就被发起了,这一处理时间和I/O时间可能有很大一部分重叠。
当DBMS请求一个页时,磁盘系统可能会将接下来一组页加载至磁盘缓冲区中(它预测这些页可能很快就会被请求到)。
大部分的数据库写都是异步的,以达到对性能的影响最小化。这一方式导致的最主要的影响时加重了磁盘环境的负载,而这反过来会影响读I/O的性能。