实验环境:

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. 用app.net Core搞点多国语言网站

    Asp.net Core 中文文档很少,你可以看英文的,不过英文的也是说的有点乱.这篇文章是干货. 1. 配置好你的WebApplication,使他可以支持国际化语言,修改文档Startup.cs ...

  2. LINQ之LINQ to Objects(上)

    LINQ概述 LINQ,语言集成查询(Language Integrated Query),它允许使用C#或VB代码以查询数据库相同的方式来操作不同的数据源. 1.LINQ体系结构 从上图可以看出,L ...

  3. struts2.1.6教程一、准备工作及实例

    1.解压struts-2.1.6-all.zip apps目录:struts2自带的例子程序 docs目录:官方文档. lib 目录:存放所有jar文件. Src 目录:源文%件存放地 2.六个基本包 ...

  4. 小tips:用java模拟小球做抛物线运动

    这几天刚刚学习了java线程,然后跟着书做了几个关于线程的练习,其中有一个练习题是小球动起来.这个相信很简单,只要运用线程就轻松能够实现.然后看到了它的一个课后思考题,怎样让小球做个抛物线运动,这点我 ...

  5. haproxy-代码阅读-内存管理

    haproxy内存池概述 内存池按照类型分类,每个类型的内存池都有一个名字,用链表记录空闲的内存块,每个内存块大小相等,并按照16字节对齐. haporxy用pool_head 结构记录内存池 str ...

  6. Android WebView 不支持 H5 input type="file" 解决方法

    最近因为赶项目进度,因此将本来要用原生控件实现的界面,自己做了H5并嵌入webview中.发现点击H5中 标签 不能打开android资源管理器. 通过网络搜索发现是因为 android webvie ...

  7. nodeJS实战:自定义模块与引入,不同模块的函数传递及回调处理,exports与module.exports(基于nodejs6.2.0)

    前言:本文基于上一篇文章中的源代码进行改写,地址:http://blog.csdn.net/eguid_1/article/details/52182386 注意:为什么不用module.export ...

  8. bootstrap之daterangepicker---汉化以及扩展

    一.扩展的功能 1.初始化时,会自动创建一个select标签: 2.当改变select值时,日期也会自动改变,并且会调用apply按钮的click事件 3.点击此处进行预览 4.github地址:ht ...

  9. eclipse在线安装s

    1. 打开eclipse软件,点击菜单栏的help-->Install New Software 2. 在弹出来的安装窗口中,点击add按钮,然后输入svn安装地址:http://subclip ...

  10. [0] 关于IComparable和IComparer接口和Comparer类

    关于IComparable和IComparer接口 和 Comparer类 IComparable和ICompareframeworkr接口是.net 中比较对象的标准方式,这两个接口之间的区别如下: ...