据说这是一个2010年阿里面试Oracle DBA的面试题,来自某公众号,作者当年面试阿里Oracle DBA时亲历,称之为“拒人于千里之外的SQL题”:
“有一张以 ID 为主关键字的聚集表,表数据量是 2 亿。要将另一张同样结构的表,表数据量是 6000 万,合并到第一张表里。
请你设计一个更新的过程。第一张表可能含有 第二张表的部分数据,也可能没有。没有的要插入,匹配的要更新。”
这是一个典型的merge操作,只不过数据量大了一些。表上有没有分区,占用多少存储空间,有多少索引,是否需要中断业务,这些都是比较重要的条件,都没有提及,说明这是一个开放式的问题。
作者在文章中没有给出解题思路,我谈谈自己的想法:
方法1、不管表有没有分区,直接用merge,开启并行dml,这个数据量在硬件条件还可以的系统,也不是问题,与方法2、3相比,效率就一般般。这个方法的关键是要开启并行dml。知道使用merge,能得点分;再加上会启用并行dml,应该也能勉强及格吧。这个要看面试官出题的出发点了。
方法2、还是merge,两个表都设计成按id 做相同hash 分区的分区表,同时开启并行DML,效率会有很大提升,因为这个会用到oracle的partition wise join技术。在硬件条件(主要是存储吞吐量)还可以的情况下,开个32个并行,如果没有索引,一两分钟应该能解决战斗。如果面试者在2010年能知道PWJ这个知识点,这个答案过面试官这一关应该没问题,因为到了2019年,了解这个知识点的人也不多(在某些书上还能看到有优化大师用手工实现类似partition wise join实现的方法,不知道是不是不想用并行的缘故。大表做类似操作,并行必须用啊)。
方法3、创建相同表结构新表,原来两表做full outer join,插入数据到新表,然后再rename,这种方法效率最高。如果表上还有索引,那更是首选方法,可以插入数据后再创建索引。这个方法再配合partition wise join、并行dml、nologging、compress技术,如果存储够强悍,一分钟内解决战斗完全没问题。
方法4、11g版本开始提供了一个分片并行的方法:DBMS_PARALLEL_EXECUTE。可以把6000万的表,按照rowid或是其他方式进行分片(本题不能对2亿的表做分片),如果有60个分片,那么每个分片只需要处理100万记录即可。这种方法需要使用plsql,操作起来有点复杂。每个100万记录的分片与2亿记录的表做merge,如果逐条做Nested loop,走索引效率不高;如果用Hash join,则2亿大表要扫描60次,效率都不行。优点就是可以减少回滚段的使用(相比方法1和2)。这种方法可能也是很多程序员的思维,大表分段,开启游标,逐条处理,效率是真的不行。
总结:
方法3效率最高;方法2简单高效,需要分区配合;方法1效率一般;方法4对单表操作的dml还可以,在本例,也不合适。
上面是我能想到的几个方法,不知道阿里的面试官自己的出题和解题思路是什么,说不定还有更高级的方法。
(完)
本文分享自 老虎刘谈oracle性能优化 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!