Mysql数据查询逻辑

发布时间 2023-10-30 18:09:19作者: Silentdoer

MySQL是一定有一个唯一非空索引的,如果有主键则是主键,没有主键则是用唯一键,唯一键也没有则会自动生成一个隐藏的字段作为主键;然后以这个字段作为聚簇索引;

所以比如表foo,它的每一行的所有列数据是连续的(至少每一列数据的“指针”值在行里是连续的,比如text这种列,在一行里可能只是存储的它的“指针”)

而行与行之间则不是连续的了,比如第一行的数据起始地址是0,结束地址是100;第二行数据的起始地址可能是150,结束地址是250;

所以我们select* from foo where name = 'aaa',如果name不是索引字段该怎么查出符合条件的行呢?【mysql可以直接将一个表的数据放到一个文件里就可以了;一个表的index也可以放单独的文件里】

就是通过聚簇索引得到所有行的起始地址,如:[0, 150, 340, 800, 1230, ...],然后再去找每一行的name字段(这个是固定的,因为它相对起始地址的偏移量对每一行都是固定的,字段类型也是固定的,因此寻址逻辑是固定的)的值要遍历所有的行找到name字段值对比一下,符合则把这行拿出来;

如果行数据量特别大的时候就会出现性能问题;

而如果我们给name加了索引,比如B+数;即是按算法排好序的name list,这样我们查这个list就能快速的查出符合条件的name列表;举个简单的例子,比如索引的字段age是数值,那么这个索引存储起来大概是这样:[(1, addr1), (1, addr2), (3, addr6), (3, addr9), (5, addr13), (8, addr18)],这里元组第一个字段值就是索引字段值,第二个字段就是对应的行地址,且是按索引字段值从小到大排好了序;

这样我们要找age=3的,我们就可以根据二分法或者其他搜索方法快速得出第三个和第四个元素是符合条件的记录,拿出addr6和addr9这两条记录;

 

总结:行式数据(MySQL等)是将一行的所有列的数据或数据的“指针”放到连续空间里;

而列式数据(如ClickHouse)则是将 一列的所有行数据/数据指针 放到连续的空间里(应该只能是指针,因为针对用户而言是“行”是很多行的,比如10W行,即在ck里则每一“行”都是有10W“列”);注意,每一列的数据都是经过排序的(网上是这么说的,待确认,因为每列都是排序的,排完序后列age和列name的第一个元素基本不太可能是插入时的同一条记录;比如select name, age from ck_bar where age = 1,age=1它可能在age列里是第一条数据,它怎么和插入时的name='ddd'关联起来?假设'ddd'在name列是第四个元素);所以执行select name from ck_bar where name = 'aaa'是会很快的;但是如果涉及多列的时候则会很慢?