实验环境:

DB is PostgreSQL version 8.2.15

JDK1.8

测试一

使用JDBC查询一个SQL:

public static void test1(String url, Properties props){
String sql = "SELECT l.src_ip, l.location_id, "
+ "SUM(l.us_bytes) as up_usage, "
+ "SUM(l.ds_bytes) as down_usage, "
+ "(SUM(l.us_bytes) + SUM(l.ds_bytes) ) as total_usage "
+ "FROM unmapped_endpoint_location_hours l "
+ "where l.org_id = 195078 "
+ "AND date_time >= '2017-04-01 00:00:00.0' AND date_time < '2017-04-08 00:00:00.0' "
+ "AND l.location_id in (2638,2640,2654 ) "
+ "GROUP BY l.src_ip, l.location_id "; Connection conn = null;
Statement sta = null;
try {
System.out.println("Start query1:" );
long s_time = System.currentTimeMillis();
conn = DriverManager.getConnection(url, props);
sta = conn.createStatement();
sta.execute(sql);
System.out.println("Using Time: " + (System.currentTimeMillis() - s_time));
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (sta != null) {
try {
sta.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}

结果:

Start query1:
Using Time: 11519 ms

测试二

使用JDBC PreparedStatement 查询相同的SQL:

public static void test2(String url, Properties props){
String sql2 = "SELECT l.src_ip, l.location_id, "
+ "SUM(l.us_bytes) as up_usage, "
+ "SUM(l.ds_bytes) as down_usage, "
+ "(SUM(l.us_bytes) + SUM(l.ds_bytes) ) as total_usage "
+ "FROM unmapped_endpoint_location_hours l "
+ "where l.org_id = ? "
+ "AND date_time >= ? AND date_time < ? "
+ "AND l.location_id in (2638,2640,2654 ) "
+ "GROUP BY l.src_ip, l.location_id"; Connection conn = null;
PreparedStatement preSta = null;
try {
System.out.println("Start query2:");
long s_time = System.currentTimeMillis();
conn = DriverManager.getConnection(url, props);
preSta = conn.prepareStatement(sql2);
preSta.setString(1, "195078");
preSta.setString(2, "2017-04-01 00:00:00.0");
preSta.setString(3, "2017-04-09 00:00:00.0");
preSta.executeQuery();
System.out.println("Using Time: " + (System.currentTimeMillis() - s_time));
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (preSta != null) {
try {
preSta.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}

结果:

Start query2:
Using Time: 143031 ms

相同的SQL,测试二和测试一结果为什么差别这么大?

测试一的SQL没有使用PreparedStatement 方式,直接给了原始的SQL。测试二的使用了PreparedStatement ,但是在set参数的时候用的都是String。

两者查询速度相差10倍,这是不是很奇怪?

现在来做另一个实验:

测试三

使用JDBC PreparedStatement 查询相同的SQL:

public static void test3(String url, Properties props){
String sql2 = "SELECT l.src_ip, l.location_id, "
+ "SUM(l.us_bytes) as up_usage, "
+ "SUM(l.ds_bytes) as down_usage, "
+ "(SUM(l.us_bytes) + SUM(l.ds_bytes) ) as total_usage "
+ "FROM unmapped_endpoint_location_hours l "
+ "where l.org_id = ? "
+ "AND date_time >= ? AND date_time < ? "
+ "AND l.location_id in (2638,2640,2654 ) "
+ "GROUP BY l.src_ip, l.location_id"; Connection conn = null;
PreparedStatement preSta = null;
try {
System.out.println("Start query3:");
long s_time = System.currentTimeMillis();
conn = DriverManager.getConnection(url, props);
preSta = conn.prepareStatement(sql2); int org_id = 195078;
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
Date d1 = null;
Date d2 = null;
try {
d1 = df.parse("2017-04-01 00:00:00");
d2 = df.parse("2017-04-09 00:00:00");
} catch (ParseException e1) {
e1.printStackTrace();
}
preSta.setInt(1, org_id);
preSta.setTimestamp(2, new java.sql.Timestamp(d1.getTime()));
preSta.setTimestamp(3, new java.sql.Timestamp(d2.getTime()));
preSta.executeQuery();
System.out.println("Using Time: " + (System.currentTimeMillis() - s_time));
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (preSta != null) {
try {
preSta.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}

结果:

Start query3:
Using Time: 16245 ms

测试结果和测试一的结果差不多,为什么?

这次测试同样使用了PreparedStatement,但是在设置参数的时候指定了参数的类型。

explan analyze

查看explan

dev=# explain analyze SELECT count(loc.name) AS totalNum
dev-# FROM (SELECT t.src_ip, t.location_id, t.up_usage, t.down_usage, t.total_usage
dev(# FROM (SELECT l.src_ip, l.location_id,
dev(# SUM(l.us_bytes) as up_usage,
dev(# SUM(l.ds_bytes) as down_usage,
dev(# (SUM(l.us_bytes) + SUM(l.ds_bytes) ) as total_usage
dev(# FROM unmapped_endpoint_location_hours l
dev(# where l.org_id = 195078
dev(# AND date_time >= '2017-04-11 00:00:00.0' AND date_time < '2017-04-20 00:00:00.0'
dev(# AND l.location_id in (2638,2640)
dev(# GROUP BY l.src_ip, l.location_id ) t
dev(# WHERE t.total_usage > 0.0 ) m
dev-# LEFT OUTER JOIN locations loc on m.location_id = loc.id WHERE loc.org_id = 195078;

Time: 15202.518 ms

Prepare Expalin:

PREPARE  test(int,text,text,int) as
SELECT count(loc.name) AS totalNum
FROM (SELECT t.src_ip, t.location_id, t.up_usage, t.down_usage, t.total_usage
FROM (SELECT l.src_ip, l.location_id,
SUM(l.us_bytes) as up_usage,
SUM(l.ds_bytes) as down_usage,
(SUM(l.us_bytes) + SUM(l.ds_bytes) ) as total_usage
FROM unmapped_endpoint_location_hours l
where l.org_id = $1
AND date_time >= $2 AND date_time < $3
AND l.location_id in (2638,2640)
GROUP BY l.src_ip, l.location_id ) t
WHERE t.total_usage > 0.0 ) m
LEFT OUTER JOIN locations loc on m.location_id = loc.id WHERE loc.org_id = $4; Explain analyze EXECUTE test(195078,'2017-04-11 00:00:00.0','2017-04-20 00:00:00.0',195078);
dev=# EXECUTE test(195078,'2017-04-11 00:00:00.0','2017-04-20 00:00:00.0',195078);

Time: 98794.544 ms

结论

PostgreSQL 在使用原始SQL的时候会用表中类型来查,能有效根据where条件过滤结果。

当参数都是使用String的时候,没有指定类型时,PostgreSQL没有先做类型转换,而是扫描了所有的数据,对所有的数据根据where条件过滤结果。

当查询参数指定类型的时候,PostgreSQL可以先根据where条件过滤结果。

相关连接:

It seems when using JDBC with prepare statement, the query will be slow in postgresql:

http://www.postgresql-archive.org/Slow-statement-when-using-JDBC-td3368379.html

http://grokbase.com/t/postgresql/pgsql-general/116t4ewawk/reusing-cached-prepared-statement-slow-after-5-executions

https://stackoverflow.com/questions/28236827/preparedstatement-very-slow-but-manual-query-quick

PostgreSQL 使用 PreparedStatement 导致查询慢的分析的更多相关文章

  1. 1125MySQL Sending data导致查询很慢的问题详细分析

    -- 问题1 tablename使用主键索引反而比idx_ref_id慢的原因EXPLAIN SELECT SQL_NO_CACHE COUNT(id) FROM dbname.tbname FORC ...

  2. SQL SERVER 查询性能优化——分析事务与锁(五)

    SQL SERVER 查询性能优化——分析事务与锁(一) SQL SERVER 查询性能优化——分析事务与锁(二) SQL SERVER 查询性能优化——分析事务与锁(三) 上接SQL SERVER ...

  3. 使用Django.core.cache操作Memcached导致性能不稳定的分析过程

    使用Django.core.cache操作Memcached导致性能不稳定的分析过程 最近测试一项目,用到了Nginx缓存服务,那可真是快啊!2Gb带宽都轻易耗尽. 不过Api接口无法简单使用Ngin ...

  4. ORACLE中的TOP-N查询(TOP-N分析)、分页查询

    TOP-N查询(TOP-N分析):就是获取某一数据集合中的前N条记录,实际应用中经常用到. Oracle中不支持SELECT TOP语句(MySQL中也没用此语句),需要借助ROWNUM伪列来实现TO ...

  5. sql查询速度慢分析及如何优化查询

    原因分析后台数据库中数据过多,未做数据优化数据请求-解析-展示处理不当 网络问题提高数据库查询的速度方案SQL 查询速度慢的原因有很多,常见的有以下几种:1.没有索引或者没有用到索引(查询慢最常见的问 ...

  6. alias导致virtualenv异常的分析和解法

    title: alias导致virtualenv异常的分析和解法 toc: true comments: true date: 2016-06-27 23:40:56 tags: [OS X, ZSH ...

  7. SQLServer查询执行计划分析 - 案例

    SQLServer查询执行计划分析 - 案例 http://pan.baidu.com/s/1pJ0gLjP 包括学习笔记.书.样例库

  8. [转]DllMain中不当操作导致死锁问题的分析——DllMain中要谨慎写代码(完结篇)

    在CSDN中发现这篇文章,讲解的比较详细,所以在这里备份一个.原文链接:http://blog.csdn.net/breaksoftware/article/details/8167641 DllMa ...

  9. oracle分页查询及原理分析(总结)

    oracle分页查询及原理分析(总结) oracle分页查询是开发总为常用的语句之一,一般情况下公司框架会提供只需套用,对于增删改查而言,查是其中最为关键也是最为难的一块,其中就有使用率最高的分页查询 ...

随机推荐

  1. Day3-递归函数、高阶函数、匿名函数

    一.递归函数 定义:函数内部可以调用其它函数,如果调用自身,就叫递归. 递归特性: 1.必须有结束条件退出: >>> def calc(n): ... print(n) ... re ...

  2. prop()、attr()和data()

    设置元素属性,用attr()还是prop()? 对于取值为true /false的属性,如 checked/selected/readonly或者disabled,使用prop(),其他属性使用 at ...

  3. MSICE界面和功能分析

    一.首页 ICE实现的这种界面样式,有可能使用WCF实现的,但是MFC来模仿也是可行的. 包括配置界面,和右下角的细节. 首页的主要功能只有3个,分别为图片拼接.视频拼接和打开拼接文件. 二.输入拼接 ...

  4. 开涛spring3(4.4) - 资源 之 4.4 Resource通配符路径

    4.4.1  使用路径通配符加载Resource 前面介绍的资源路径都是非常简单的一个路径匹配一个资源,Spring还提供了一种更强大的Ant模式通配符匹配,从能一个路径匹配一批资源. Ant路径通配 ...

  5. Swift 入门之简单语法(二)

    可选项判断 由于可选项的内容可能为 nil,而一旦为 nil 则不允许参与计算 因此使用中,经常需要判断可选项的内容是否为 nil 单个可选项判断 let url = NSURL(string: &q ...

  6. 模仿ICE的structured panorama小按钮

    这个按钮的目的是用于手动排列图片序列,应该说写得比较精巧,我使用csharp进行模仿,主要采用的是自动控件创建技术.结果比较简陋,实现功能而已,放出来大家一起学习. ;        ;        ...

  7. R实现地理位置与经纬度相互转换

    本实例要实现目标通过输入城市名或者地名,然后找出其经度纬度值,以及通过可视化展现其线路流向以及周边地图展示 address_list数据: 山西省太原市小店区亲贤北街77号 贵州省贵阳市云岩区书香门第 ...

  8. [HDU1020] Encoding - 加密

    Problem Description Given a string containing only 'A' - 'Z', we could encode it using the following ...

  9. 一天搞定CSS:文本text--05

    1.文本体系 2.文本各属性取值 说明: 每一个属性后面的分支是属性值,以及对属性值的说明. 比如text-align- - - -有3个取值:left,center,right 3.空格大小 4.代 ...

  10. Java-集合框架总结

    集合框架: Java中的集合框架大类可分为Collection和Map:两者的区别: 1.Collection是单列集合:Map是双列集合 2.Collection中只有Set系列要求元素唯一:Map ...