Bitmaps-位图
比特位图可以使用少量的空间而提供大量的信息。
例如,某程序中,我们可能需要8个变量存储一些信息:
- Bolean isFemale:是否是女性
- Bolean isJobless:是否失业
- Bolean isFat:是否肥胖
- Bolean isTall:是否高大
- Bolean isStudent:是否为学生
- Bolean isGraduate:是否为研究生
- Bolean isBeijing:是否为北京人
- Bolean isMarried:是否已婚
如此一来,这8个变量至少占用8个字节。但若采用位图,一个字节足矣。我们采用一个比特位代表true和false值,上面8个变量就可以缩写为01000010,以表示该男性目前处于未婚失业状态,户口所在地为北京,无研究生学历,总共占用一个字节。这样既可以节省空姐,还可以提高处理速度(也可称“位图”为“位映射”)。
MySQL中的mysys目录下的my_bitmap.c文件中包含了各种操作位图的函数:
- 设置和拆除操作(bitmap_init、bitmap_free)
- 设置和清理整个比特位图或某个具体的比特位(bitmap_set_bit、bitmap_fast_test_and_set、bitmap_clear_all、bitmap_set_all)
- 对两个比特位图进行比较操作(bitmap_cmp、bitmap_intersect、bitmap_subtract、bitmap_union)
比特位图的缺陷:
- 系统为位图分配空间的最小单位是字节、即8个比特位。某些情况下我们未必会使用完8*n个比特位,这种情况下造成无法知道位图最后几位是否有意义
- 比特位图的比较操作bitmap_union要操作的两个比特位图必须是等长的
- 整个比特位图包含了大量的有用关键信息,多个县城对同一比特位图变量操作时,要借助互斥锁(Mutex)的帮助。互斥锁可能导致线程串行化
MySQL排序实现
查询语句中的order by和group by 都是很耗时的操作,本节我们将学习到MySQL实现排序功能的背后原理。大致来说,MySQL的排序方式有两种:
- 第一类是使用range、ref、index读写方式。explain的输出range、ref、index是描述对索引列的读取方式。到MySQL5.4版位置,这些方式获得的输出都是按照索引的顺序排列的,所以这类方式读取后,我们就不需要进行排序操作。但是在MySQL6.0及之后的版本中,MyISAM和InnoDB使用多段读取(MRR)的方式。
- 第二类方式,使用filesort排序算法。简单来说,filesort算法就是将一组记录或元祖按照快速排序算法放入到内存缓存,然后这几个内存缓存按照合并算法排序。filesort算法能共使用的内存数由系统参数@@sort_buffer_size控制。若被排序数据大于@@sort_buffer_size,filesort算法会创建一个临时表来存放数据,这样将导致系统性能下降。
Filesort的数据通常来自于一个表。若数据来自多个表则filesort的做法会略有不同,系统首先将多个表的数据放入到临时表中,然后调用filesort对这个临时表进行操作。
Filesort的工作模式也有两种:
- 直接模式:我们已经将要求排序的数据完全读取,经过排序后的数据就是我们需要的结果
- 指针模式:排序时,数据或临时表以
<sort_key,rowid>
的形式存在。按sort_key排序后,根据rowid找到数据记录,最后读取我们所需要的数据。结果排序后,包含的所有列就是我们需要的列。
注:MySQL一般会使用直接模式,指针模式只有在直接模式不可行时才被采用。那么什么情况下直接模式不可行呢?
当被排序的记录中包含Blob等变长字段时,直接模式是不可行的。不过,explain的输出并没有告诉我们MySQL filesort到底采用直接模式还是指针模式,所以只能手动查看输出结果中是否有Blob等类型。
以下以带order by 或 group by 的 join 操作为例,说明MySQL可能执行排序的三种方法。
方法 | Explain的输出 |
1、使用已排序索引 | Explain不会提及任何filesort |
2、在表单中使用filesort | using filesort |
3、将join结果先放入临时表,然后使用filesort | using temporary, Using filesort |
在第一种方法中,表join操作中的第一个表有索引且索引就是order by的某一列,并且order by的其他字段也都包含在其他表中,那么我们采用该算法。
当我们使用的order by列均在join操作的第一个表上时,MySQL可能采用第二种方法排序。这种情况下,MySQL先对第一个表进行排序,然后将排序的表与其他表进行连接。