浅谈大数据量下数据库查询插入的优化

2018-01-11 12:51:51来源:oschina作者:小欣妹妹人点击

分享
第七城市

数据库经常要做一些查询与插入,但是如果查询和插入的数据量过大的时候就会引发数据库性能问题,降低数据库工作效率。因此性能调优是大家在工作中都能够预见的问题,大到世界五百强的核心系统,小到超市的库存系统,几乎都会有要调优的时候。面对形形色色的系统,林林总总的需求,调优的手段也是丰富多彩。 1.尽量使语句符合查询优化器的规则避免全表扫描而使用索引查询 2.避免频繁创建和删除临时表,以减少系统表资源的消耗。 3.尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。 4.建立高效的索引 SQL语句的Select部分只写必要的列;尽量将In子查询重写为Exists子查询; 去除在谓词列上编写的任何数学运算;尽可能不用Distinct; 由于优化工具处理“或”逻辑可能有问题,所以尽量采用其他方式重写; 确保所处理的表中数据分布和其他统计信息正确,并反映当前状况;尽可能用UNION ALL取代UNION; 尽可能减少DB2的SQL请求;尽量将区间谓词重写为Between谓词;不要只是为了排序而选择某一列; 我目前所在的系统就是这么一个有实时插入又需要大数据的查询的一个系统。 采用了如下手段: 1,当天的记录会放在一个独立的表中.主要是针对实时的插入的记录,记录不要太多以免插入的时候维护索引的开销稳定在一个范围内。 2,历史的记录会按天分区的形式保存在历史表中。这个表一天只会批量的插入一次数据(用的是分区交换的方法)。 3,分区的索引对我的业务性能不好,因为要跨天 查询。历史查询最长时间段是一个月的时间,如果按照一个月一个分区的话,一个分区差不多是一个亿的记录, 就算是按月分区的话,再创建分区的本地索引,如果是时间段跨了月份的话估计分区的本地索引性能估计也不行。 4,后来采用一个方案,DB层上面再放了一个缓冲层,就是我最近在测试的Timesten关系型内存数据库,按照时间的老化策略缓冲一个月的数据。具体不展开说了。涉及的内容很多。 只是对于这个系统,我总结一下有以下需要注意的地方: 1,对于一个系统来说,如果查询性能反应不好的话,第一个调整的地方是思考业务的需求是否是合理的? 一个查询既要分页获取前面一页或者几页的数据,又要根据条件获取总的记录数,如果符合的记录总数是上亿条的话,感觉就是一个不合理的要求。 2,市场需求调研人员业务水平根本不合格。 3,前台开发人员写的SQL差,根本没有调优的基本概念,术业有专攻啊。 4,如果业务需求合理,SQL的调整无非是从执行计划开始,如果是ORACLE10g,开了cbo,可以用 SQL优化器 (SQL Tuning Advisor :STA) 分析你的sql。 5,最近的nosq和海量分布式的数据库概念很热。公司也在考虑HBASE了。 分区, 读写分离。 细节的优化手段大家都说了很多,我说些几个粗略的方面: 1.使用分区表 2.并行查询 3.定期的数据信息采集 4.可以考虑使用sql hint(生产库上我个人认为还是少指定 HINT,可以考虑用 SQL_PROFILE固定执行计划) 对于大数据量的处理,我通常采用如下方法: 一、对于大数据存储的处理(以下是假设硬件指标合格的情况) (1)对大表进行分区,根据不同的业务以及数据特征,采用不同的分区方法。比如,销售,可以考虑采用间隔分区技术,多分公司或是多部门,可以考虑采用列表分区或是上述的组合分区等。 (2)如果硬件具备,对于大表进行分离存储,从而减少磁盘争用。 (3)对历史数据进行定期的归档处理。比如,销售的区间分区,可以采用表与分区交换的技术去处理。对于含有复杂的业务的数据表的归档,采用PL/SQL脚本与后台作业定时完成。 二、对于查询的处理(以下是基于成本优化器的情况) 对于查询,优化的方法通常会多一些,但是也是最频繁调整的一块内容。通常,我从如下这几个方面来进行考虑并调优. (1)对于SQL本身的编写是否合理。比如基础写法与高级写法之间的配合,在满足业务要求的基础上,做到尽量减少表的访问。 (2)索引的创建是否合理,优化器是否选择了较正确的索引。在不同的业务场景下,B*树索引与位图索引的相互配合是否合理等。 (3)监控系统中产生的争用,根据产生的不同的闩或锁,对SQL或是业务处理逻辑进行调整。 (4)如果有必要,根据当前系统的负载与硬件本身的支持,对PGA,SGA进行一个分配,使之更为合理。 (5)如果有必要,在优化器参数进行一个调整。 (6)采用并行处理。 三、对数据插入的处理 这是考虑问题当中最薄弱的一块内容,一般不作必要的优化处理,但有如下一些技巧: (1)对于大数据量的表与表之间的插入,可以采用并行,直接路径、最小化日志。 (2)如果必要,对表本身参数进行一个修改,如freelist。 (3)如果是同数据源多目标的插入,可以采用多表插入技术。 (4)如果可以,尽量使用INSERT INTO SELECT,CREATE TABLE AS SELECT方法。 如果在前期需求调研,设计阶段就做好了工作。那么后面的性能优化问题麻烦就可以少很多。 当然通常由于各种原因,往往前期做不到那么好。 那么找到问题,发现问题,解决问题,通常 1. 通过工具来定位问题,例如选择用10046 TRACE 工具包来实现 2. 找到问题所在以后去理解需求,探索是否能少做事完成需求(选择用索引来替代全表扫描,从而减少访问路径); 3. 去思考需求背后的真正需求,例如是否可以用UNION ALL取代UNION ,避免不必要的排序引起资源消耗。 4. 去分析资源如何合理应用 (在系统空闲时使用并行技术)。 5.诊断索引方面的问题。例如是否由于错误的优化器统计信息导致执行了不正确的执行计划。 数据库表进行插入、查询操作当数据达到百万甚至千万条级别的时候, 这一切似乎变得相当困难。几经折腾,总算完成了任务。在此做些简单的小结,不足之处,还望高手们帮忙补充补充! 1、避免使用Hibernate框架 Hibernate用起来虽然方便,但对于海量数据的操作显得力不从心。 关于插入: 试过用Hibernate一次性进行5万条左右数据的插入,若ID使用sequence方式生成,Hibernate将分5万次从数据库取得 5万个sequence,构造成相应对象后,再分五万次将数据保存到数据库。花了我十分钟时间。主要的时间不是花在插入上,而是花在5万次从数据库取 sequence上,弄得我相当郁闷。虽然后来把ID生成方式改成increase解决了问题,但还是对那十分钟的等待心有余悸。 关于查询: Hibernate对数据库查询的主要思想还是面向对象的,这将使许多我们不需要查询的数据占用了大量的系统资源(包括数据库资源和本地资 源)。由于对Hibernate的偏爱,本着不抛弃、不放弃的作风,做了包括配SQL,改进SQL等等的相当多的尝试,可都以失败告终,不得不忍痛割爱 了。 2、写查询语句时,要把查询的字段一一列出 查询时不要使用类似select * from x_table的语句,要尽量使用select id,name from x_table,以避免查询出不需要的数据浪费资源。对于海量数据而言,一个字段所占用的资源和查询时间是相当可观的。 3、减少不必要的查询条件 当我们在做查询时,常常是前台提交一个查询表单到后台,后台解析这个表 单,而后进行查询操作。在我们解析表单时,为了方便起见,常常喜欢将一些不需要查询的条件用永真的条件来代替(如:select count(id) from x_table where name like ‘%’),其实这样的SQL对资源的浪费是相当可怕的。我试过对于同样的近一千万条记录的查询来说,使用select count(id) from x_table 进行表查询需要11秒,而使用select count(id) from x_table where name like ‘%’却花了33秒。 4、避免在查询时使用表连接 在做海量数据查询时,应尽量避免表连接(特别是左、右连接),万不得已要进行表连接时,被连接的另一张表数据量一定不能太大,若连接的另一张表也是数万条的话,那估计可以考虑重新设计库表了,因为那需要等待的时间决不是正常用户所能忍受的。 5、嵌套查询时,尽可能地在第一次select就把查询范围缩到最小 在有多个select嵌套查询的时候,应尽量在最内层就把所要查询的范围缩到最小,能分页的先分页。很多时候,就是这样简单地把分页放到内层查询里,对查询效率来说能形成质的变化。 特别是银行系统的,数量级是亿级别的,所以更要考虑下面的方法。 1,怎样造Java对象。有句话说得好:尽可能的少造对象。别说千万级,就是上万级都不要考虑造对象了。因为几个请求一并发,喀嚓,系统肯定完蛋。 2,合理摆正系统设计的位置。大量数据操作,和少量数据操作一定是分开的。大量的数据操作,肯定不是ORM框架搞定的。绝对不能ORM,因为1,要少造对象;2,数据库资源合理利用。就像博主的例子:id分配就是一个好例子。 3,合理利用数据库的分区、索引技术。 4,有的时候可以考虑临时表之类的,尤其是大数据量。 5,有人说非常大的数据量,一定要用存储过程:jdbc,效果非常好 6,控制好内存,让数据流起来,而不是全部读到内存再处理,而是边读取边处理; 7,合理利用内存,有的数据要缓存。

第七城市

最新文章

123

最新摄影

闪念基因

微信扫一扫

第七城市微信公众平台