在软件系统中,为了实现计算和存储的优化,会对原始数据做各种中间形态转换,如字典映射,压缩等等。但是数据最后还是要表现它的真实形态的(真实形态才有意义),这时候就需要通过物化,将中间形态转换为原始形态。
延迟物化就是尽可能将这个过程延后。
比方说tidb。里面数据是通过chunk来传递的,那么如果一个chunk中有些数据是有效的,有些数据是无效的,那么就可以使用延迟物化技术,构建一个数组来记录有效的行,等最后在将这些行抽出来做成一个新的chunk。
如果不使用延迟物化,那么每次都构建新chunk,性能损耗就太大了。
(之前只知道了逻辑地址和物理地址的区别,对于映射关系这块我真没有太深入。然后人家问了,我不会。)
这里是根据页式内存管理来工作的。浅析逻辑地址与物理地址映射关系_朱里安的博客-CSDN博客_逻辑页号与物理页号的对应关系
先通过逻辑地址获取逻辑页号和页内偏移量。
然后可以通过页式内存管理来寻找到对应的物理页号,转换成物理地址。
其实我是觉得这个和数据库没有啥关系。
PolarDB MySQL 深潜 - 揭秘窗口函数将子查询解关联 - 知乎
简单来说,就是将子查询转化为join查询。
根据条件可以转化成join/outer join/semi join/anti join。
此时的where条件就变成了浮渣存的where条件,可以进行on条件的转换。
另外子查询还要分成关联子查询和非关联子查询。
关联子查询采用join的形式,非关联子查询根据数据量转为join或者是where。
并行(parallel):指在同一时刻,有多条指令在多个处理器上同时执行。就好像两个人各拿一把铁锨在挖坑,一小时后,每人一个大坑。所以无论从微观还是从宏观来看,二者都是一起执行的。
并发(concurrency):指在同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行,使得在宏观上具有多个进程同时执行的效果,但在微观上并不是同时执行的,只是把时间分成若干段,使多个进程快速交替的执行。这就好像两个人用同一把铁锨,轮流挖坑,一小时后,两个人各挖一个小一点的坑,要想挖两个大一点得坑,一定会用两个小时。
和seminjoin类似,但是相反,是在如果完全没有匹配的时候才会进行join,补空值,并返回数据。
适用于使用 not in的场景,比如
select * from a where a.id not in(selet b.id from b) 转换成
select * from a anti join b on a.id=b.id
(这个涉及到的范围比较广了,目前我对cbo那块也不是很熟悉,所以更详细的先搁置)
是使用cbo查询优化实现的。
对于两张表的join,比较简单,可以基于数据量多少进行位置转换。
对于多张表的join,就会变得很复杂,搜索空间会很大,可以使用贪心,动归,记忆化搜索等来减少搜索空间。可以参照一下tidb的实现方式
1.死锁问题
2.加锁问题,资源抢占
3.内存同步问题,假并行,不同的cpu对数据读写,多次加载cache。
4.线程之间协调的开销,上下文切换开销
5.出现阻塞,生产者消费者协调问题
(如果要深入问,可能就会问解决方式了)
两个因素将影响在锁上发生竞争的可能性;
有三种方式可以降低锁的竞争度
并发编程学习——8 学习笔记-多线程影响性能的因素_大·风的博客-CSDN博客
阻塞上:
实现阻塞行为时,可以采用自旋等待或者通过操作系统挂起被阻塞的线程。如果等待时间较短,则适合采用自旋等待方式,而如果等待时间较长,则适合采用线程挂起方式。
go的话是channel,后者。
锁上优化:
消除死锁,缩小锁的范围(空间),减少锁的粒度(时间),锁分段(一段数据用多个锁保证)。
开销上:
(如果再深入,可能会问线程的几个状态,和怎么切换)
【五分钟面试题】线程的生命周期和状态切换_是fancy呀的博客-CSDN博客
线程一共有以下几种状态:
1、新建状态(New):新创建了一个线程对象。
2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于“可运行线程池”中,变得可运行,只等待获取CPU的使用权。即在就绪状态的进程除CPU之外,其它的运行所需资源都已全部获得。
3、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。
阻塞的情况分三种:
(1)、等待阻塞:运行的线程执行wait()方法,该线程会释放占用的所有资源,JVM会把该线程放入“等待池”中。进入这个状态后,是不能自动唤醒的,必须依靠其他线程调用notify()或notifyAll()方法才能被唤醒,
(2)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入“锁池”中。
(3)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
5、死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
(不太好写,最起码当时我是没写出的,需要时间再考虑一下)