最近在写一个java的爬虫程序时,遇到了一个大量数据进行插入更新和大量数据循环查询的问题,所以查了一下一般的调优的方式,下面主要介绍我采取的调优措施。

一 、调优思路

先说说我采取方式的调优的思路,这样便于理解我的选取的调优策略。

思路分析

首先我们都知道计算机存储空间分为:寄存器、高速缓存、内存、交换区(外部存储虚拟化)、硬盘以及其他的外部存储。而且我们都知道从寄存器开始到硬盘读写速度是从快到慢依次递减。我们访问数据库,一般是通过运行的代码去访问数据库,运行起来的代码所需要的数据一般会放在内存或者是在高速缓存中,而数据库数据存放在哪?很多人会说应该存放在电脑硬盘中,但是这个只回答对了一半。个人开发,代码和数据库在同一个电脑上,但是如果是团队开发喃?明显存放在个人的电脑上不合适,一般会存放在团队开发的服务器上硬盘上。团队开发时,将服务器硬盘上的数据读到自己开发电脑的内存中(自己开发测试时)或者上线后从一个数据库服务器硬盘读到上线服务器内存(数据库和程序不在一个服务器上),加上数据表查询和查询交互的一些准备(包括一些初始化)所需要的时间将会很多。

最简朴的sql插入、更新和查询一般程序一条一条的链接数据库进行操作,这样耗费的时间非常恐怖。

由此引出我们调优的想法,减少与数据库交互的次数,将多条查询,多条插入,多条更新合并为交互一次,也就是批操作。这样会减少很多时间。多次处理的操作交给java程序在内存中进行处理,内存中处理的速度要快上很多。

二、插入的优化(批插入)

将插入语句进行拼接,多条插入语句拼接成一条插入语句,与数据库交互一次执行一次。

使用insert into tableName values(),(),(),()语句进行拼接然后再一次性插入。

如果字符串太长,则需要配置下MYSQL,在mysql 命令行中运行 :set global max_allowed_packet = 2*1024*1024*10

我插入1000条的数据耗时为毫秒级别,效率提高很多。

1、下面是代码可以便于理解:

$sql= "insert into twenty_million (value) values";
for($i=0;$i<2000000;$i++){
$sql.="(''),";
};
$sql = substr($sql,0,strlen($sql)-1);
$connect_mysql->query($sql);

2、我是用java写的代码,用的是spring带的JdbcDaoSupport类写的dao层,所以粘一下代码

 public void batchInsert(List<SpdrGoldEtfPostions> spdrGoldEtfPostionsList) {
int size = spdrGoldEtfPostionsList.size();
String sql = "insert into " + TABLE_NAME + "(" + COLUMN_WITHOUT_ID + ") values";
StringBuffer sbf = new StringBuffer(sql);
for (int i = 0; i < size - 1; i++) {
sbf.append("('").append(spdrGoldEtfPostionsList.get(i).getSpdrEftId()).append("','")
.append(spdrGoldEtfPostionsList.get(i).getSpdrEftDate())
.append("',");
sbf.append(spdrGoldEtfPostionsList.get(i).getTotalNetAssetValue()).append("),");
}
sbf.append("('").append(spdrGoldEtfPostionsList.get(size - 1).getSpdrEftId()).append("','")
.append(spdrGoldEtfPostionsList.get(size - 1).getSpdrEftDate())
.append("',");
sbf.append(spdrGoldEtfPostionsList.get(size - 1).getTotalNetAssetValue()).append(")"); sql = sbf.toString();
this.getJdbcTemplate().update(sql);
}

三、更新优化(批更新)

将更新语句进行拼接,多条更新语句拼接成一条更新语句,与数据库交互一次执行一次。

1、下面是sql语句的批更新语句,提供便于理解

UPDATE book
SET Author = CASE id
WHEN 1 THEN '黄飞鸿'
WHEN 2 THEN '方世玉'
WHEN 3 THEN '洪熙官'
END
WHERE id IN (1,2,3)

2、下面java写的spring带的JdbcDaoSupport类写的dao层的批更新语句

  public void batchUpdateBySpdrEftDate(List<SpdrGoldEtfPostions> spdrGoldEtfList) {
int size = spdrGoldEtfList.size();
String sql = "UPDATE " + TABLE_NAME + " set total_net_asset_value = CASE spdr_eft_date\n";
StringBuffer sbf = new StringBuffer(sql);
for (int i = 0; i < size; i++) {
sbf.append("WHEN ").append(spdrGoldEtfList.get(i).getSpdrEftDate()).append(" THEN ")
.append(spdrGoldEtfList.get(i).getTotalNetAssetValue()).append("\n");
}
sbf.append("END\n").append("WHERE spdr_eft_date IN(");
for (int i = 0; i < size - 1; i++) {
sbf.append(spdrGoldEtfList.get(i).getSpdrEftDate()).append(",");
}
sbf.append(spdrGoldEtfList.get(size - 1).getSpdrEftDate()).append(")");
sql = sbf.toString();
this.getJdbcTemplate().update(sql);
}

四、查询优化(批量查询)

将所有的查询都合并为一条查询语句,然后返回一个集合,然后处理集合(最好返回的集合是有序的,这样处理起来比较的方便,在sql语句中可以用order by 或者group by进行排序分类,顺便多说一句,使用order by 和group by 的字段最好建立索引,这样速度更快)

1、首先写一下sql语句,便于大家理解

select * from tableName where id in (1,2,3,4) order by id

2、下面java写的spring带的JdbcDaoSupport类写的dao层的批查询语句

 public List<SpdrGoldEtfPostions> batchSelectBySpdrEtfDate(String[] spdrEtfDateArray) {
String sql = "select * from " + TABLE_NAME;
StringBuffer sbf = new StringBuffer(sql);
sbf.append(" where spdr_eft_date IN(");
for (int i = 0; i < spdrEtfDateArray.length - 1; i++) {
sbf.append(spdrEtfDateArray[i]).append(",");
}
sbf.append(spdrEtfDateArray[spdrEtfDateArray.length - 1]).append(")").append(" ORDER BY spdr_eft_date");
sql = sbf.toString();
List<SpdrGoldEtfPostions> items = this.getJdbcTemplate().query(sql, rowMapper());
return items;
}

当然批量查询你可以改变where后面的限定语句,也可以实现批量查询,如where id <100 and id>10(这里id<100写在前面也是优化的思路,这天语句在执行时,会先将范围控制在100以内,然后在从99给数据中进行查询限定,这也是优化,所以说,很多小细节都能体现优化),类似这类的也可以实现批量查询,根据需要改变限定条件实现批量查询。

五、删除的优化(批量删除)

其实看完了批量查询的话,就可以得到一些关于sql批量删除的想法了,无非是限定条件上动点手脚。

1、先给一下sql语句便于理解

delete from tableName where id in(1,2,3,4,5,6)

2、下面java写的spring带的JdbcDaoSupport类写的dao层的批删除语句

 public void batchDeleteBySpdrEtfDate(String[] spdrEtfDateArray) {
String sql = "delete from " + TABLE_NAME;
StringBuffer sbf = new StringBuffer(sql);
sbf.append(" where spdr_eft_date IN(");
for (int i = 0; i < spdrEtfDateArray.length - 1; i++) {
sbf.append(spdrEtfDateArray[i]).append(",");
}
sbf.append(spdrEtfDateArray[spdrEtfDateArray.length - 1]).append(")");
sql = sbf.toString();
this.getJdbcTemplate().update(sql); }

和查询同样道理的,可以通过设定where后面的限定,来实现其他的类批删除。

六、总结

1、首先,数据量较大的sql优化,采取的是批处理操作,减少与数据库的交互次数。

2、批处理的sql语句交给java程序去拼接,如果数据量较大时,可以考虑使用StringBuilder代替String,如果考虑线程安全可以考虑StringBuffer(或者其他安全的字符串处理类)拼接。

3、批查询的时候获取的集合数据建议排序,获取有序数据,这样便于后续java程序的处理。

4、一般的ORM框架都是用的sql语句,而一些sql语句的小的细节都能优化,使用时需要日积月累,平时应该时刻有优化意识。

5、使用过hibernate应该都知道,hibernate有缓存功能,一级二级缓存,这个思路符合我这篇博客优化思路,可以提一下,然后提供继续优化的思路,对于一些经常操作的数据可以设置高速缓存。

6、在使用sql语句的时候对于经常需要进行order by和group by的字段(列)建立索引,sql查询避免进行全表扫描,这些在写sql语句时需要注意。

简单的sql调优(批处理)的更多相关文章

  1. SQL调优常用方法

    在使用DBMS时经常对系统的性能有非常高的要求:不能占用过多的系统内存和 CPU资源.要尽可能快的完成的数据库操作.要有尽可能高的系统吞吐量.如果系统开发出来不能满足要求的所有性能指标,则必须对系统进 ...

  2. SQL调优

    # 问题的提出 在应用系统开发初期,由于开发数据库数据比较少,对于查询SQL语句,复杂视图的的编写等体会不出SQL语句各种写法的性能优劣,但是如果将应用 系统提交实际应用后,随着数据库中数据的增加,系 ...

  3. [SQL SERVER系列]读书笔记之SQL注入漏洞和SQL调优

    最近读了程序员的SQL金典这本书,觉得里面的SQL注入漏洞和SQL调优总结得不错,下面简单讨论下SQL注入漏洞和SQL调优. 1. SQL注入漏洞 由于“'1'='1'”这个表达式永远返回 true, ...

  4. 读书笔记之SQL注入漏洞和SQL调优

    原文:读书笔记之SQL注入漏洞和SQL调优 最近读了程序员的SQL金典这本书,觉得里面的SQL注入漏洞和SQL调优总结得不错,下面简单讨论下SQL注入漏洞和SQL调优. 1. SQL注入漏洞 由于“' ...

  5. SQL注入漏洞和SQL调优SQL注入漏洞和SQL调优

    SQL注入漏洞和SQL调优 最近读了程序员的SQL金典这本书,觉得里面的SQL注入漏洞和SQL调优总结得不错,下面简单讨论下SQL注入漏洞和SQL调优. 1. SQL注入漏洞 由于“'1'='1'”这 ...

  6. Hive 的简单使用及调优参考文档

    Hive 的简单使用及调优参考文档   HIVE的使用 命令行界面 使用一下命令查看hive的命令行页面, hive --help --service cli 简化命令为hive –h 会输出下面的这 ...

  7. Oracle SQL调优记录

    目录 一.前言 二.注意点 三.Oracle执行计划 四.调优记录 @ 一.前言 本博客只记录工作中的一次oracle sql调优记录,因为数据量过多导致的查询缓慢,一方面是因为业务太过繁杂,关联了太 ...

  8. /*+parallel(t,4)*/在SQL调优中的重要作用!

    谈谈HINT /*+parallel(t,4)*/在SQL调优中的重要作用! /*+parallel(t,4)*/在大表查询等操作中能够起到良好的效果,基于并行查询要启动并行进程.分配任务与系统资源. ...

  9. MySQL索引和SQL调优手册

    MySQL索引 MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BTree索引,哈希索引,全文索引等等.为了避免混乱,本文将只关注于BTree ...

随机推荐

  1. Algorithm --> 树中求顶点A和B共同祖先

    树中求顶点A和B共同祖先 题目: 给定一颗树,以及两个顶点A和B,求最近的共同祖先,和包含的子顶点个数? 比如:给定如下图的树,以及顶点13和8,则共同祖先为3,以3为root的子顶点共有8个

  2. SpringAOP-JDK 动态代理和 CGLIB 代理

    在 Spring 中 AOP 代理使用 JDK 动态代理和 CGLIB 代理来实现,默认如果目标对象是接口,则使用 JDK 动态代理,否则使用 CGLIB 来生成代理类. 1.JDK 动态代理 那么接 ...

  3. Jmeter 多用户同时登陆

    在做性能测试的时候,很多情况需要多用户同时登录,下单,那怎么实现多用户的同时登录呢 可以通过CSV Data Set Config组件实现参数化登录 1.新建一个存放用户名和密码的文件, 和jmete ...

  4. Android学习链接大放送

    虽然贴链接这种事情..真是一种很偷懒的做法... 但是我一个小菜鸟,果断还是要以多向别人学习为主... 好资源要和大家分享对不对! 况且..放博客里..比收藏夹的利用几率要大一点! 原作者应该也很喜欢 ...

  5. python全栈开发-Day10 装饰器(闭合函数的应用场)

    一. 装饰器 装饰器就是闭包函数的一种应用场景 什么是闭包函数?我们再来回忆一下: 闭包函数: 定义在函数内部的函数,并且该函数包含对外部函数作用域(强调:对全局作用域名字的引用不算闭包)名字的引用, ...

  6. iPhone页面的常用调试方法

    在iPhone中调试,大体上与上文 安卓中的移动页面调试 类似,区别主要是iOS系统中的一些限制,导致某些工具无法使用. 本文基于此,简要介绍在iPhone中如何调试页面. 最终可以实现在Mac平台使 ...

  7. 漫谈Java IO之普通IO流与BIO服务器

    今天来复习一下基础IO,也就是最普通的IO. 网络IO的基本知识与概念 普通IO以及BIO服务器 NIO的使用与服务器Hello world Netty的使用与服务器Hello world 输入流与输 ...

  8. Beta Scrum Day 4

    听说

  9. Beta冲刺第三天

    一.昨天的困难 没有困难. 二.今天进度 1.林洋洋:修改权限相关的资源表示,修复flex布局排版高度问题,修复文件更新问题,去除登录页面的默认账号密码,服务器部署. 2.黄腾达:修复日程首次执行时间 ...

  10. 为SRS流媒体服务器添加HLS加密功能(附源码)

    为SRS流媒体服务器添加HLS加密功能(附源码) 之前测试使用过nginx的HLS加密功能,会使用到一个叫做nginx-rtmp-module的插件,但此插件很久不更新了,网上搜索到一个中国制造的叫做 ...