PostgreSQL 使用 PreparedStatement 导致查询慢的分析
实验环境:
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
https://stackoverflow.com/questions/28236827/preparedstatement-very-slow-but-manual-query-quick
PostgreSQL 使用 PreparedStatement 导致查询慢的分析的更多相关文章
- 1125MySQL Sending data导致查询很慢的问题详细分析
-- 问题1 tablename使用主键索引反而比idx_ref_id慢的原因EXPLAIN SELECT SQL_NO_CACHE COUNT(id) FROM dbname.tbname FORC ...
- SQL SERVER 查询性能优化——分析事务与锁(五)
SQL SERVER 查询性能优化——分析事务与锁(一) SQL SERVER 查询性能优化——分析事务与锁(二) SQL SERVER 查询性能优化——分析事务与锁(三) 上接SQL SERVER ...
- 使用Django.core.cache操作Memcached导致性能不稳定的分析过程
使用Django.core.cache操作Memcached导致性能不稳定的分析过程 最近测试一项目,用到了Nginx缓存服务,那可真是快啊!2Gb带宽都轻易耗尽. 不过Api接口无法简单使用Ngin ...
- ORACLE中的TOP-N查询(TOP-N分析)、分页查询
TOP-N查询(TOP-N分析):就是获取某一数据集合中的前N条记录,实际应用中经常用到. Oracle中不支持SELECT TOP语句(MySQL中也没用此语句),需要借助ROWNUM伪列来实现TO ...
- sql查询速度慢分析及如何优化查询
原因分析后台数据库中数据过多,未做数据优化数据请求-解析-展示处理不当 网络问题提高数据库查询的速度方案SQL 查询速度慢的原因有很多,常见的有以下几种:1.没有索引或者没有用到索引(查询慢最常见的问 ...
- alias导致virtualenv异常的分析和解法
title: alias导致virtualenv异常的分析和解法 toc: true comments: true date: 2016-06-27 23:40:56 tags: [OS X, ZSH ...
- SQLServer查询执行计划分析 - 案例
SQLServer查询执行计划分析 - 案例 http://pan.baidu.com/s/1pJ0gLjP 包括学习笔记.书.样例库
- [转]DllMain中不当操作导致死锁问题的分析——DllMain中要谨慎写代码(完结篇)
在CSDN中发现这篇文章,讲解的比较详细,所以在这里备份一个.原文链接:http://blog.csdn.net/breaksoftware/article/details/8167641 DllMa ...
- oracle分页查询及原理分析(总结)
oracle分页查询及原理分析(总结) oracle分页查询是开发总为常用的语句之一,一般情况下公司框架会提供只需套用,对于增删改查而言,查是其中最为关键也是最为难的一块,其中就有使用率最高的分页查询 ...
随机推荐
- java面向对象--内部类
将一个类定义在另一个类里面,里面的那个类称为内部类,与属性.方法等一样视作外部类的成员.内部类提供了更好的封装,不允许同包中的其他类访问该内部类. 内部类作为外部类的成员,同样可以被4个访问限定符修饰 ...
- 史诗手册!微信小程序新手自学入门宝典!
一.小程序官方指南 1:官方开发工具下载: https://mp.weixin.qq.com/debug/wxadoc/dev/devtools/download.html?t=201714 0.12 ...
- Tomcat 部署项目的三种方法
1.下载 Tomcat 服务器 ①.官网下载地址:http://tomcat.apache.org/ ②.tomcat 8.0 64位百度云下载地址:http://pan.baidu.com/s/1s ...
- struts2.1.6教程六、使用标签
1.基础表单标签 准备工作:建立struts2tag项目,搭建好struts2的开发环境.在html我们常用的基础表单标签主要有文本域.密码域.提交.重置四种.它们在strust2中可以通过标签来生成 ...
- Python爬虫01——第一个小爬虫
Python小爬虫——贴吧图片的爬取 在对Python有了一定的基础学习后,进行贴吧图片抓取小程序的编写. 目标: 首先肯定要实现图片抓取这个基本功能 然后实现对用户所给的链接进行抓取 最后要有一定的 ...
- IPad分屏,当电脑第二显示屏
最在在网上看到使用IPad可以做为电脑的第二个显示屏,对于我这样一个程序猿来说,这真是我的福音呀!因此在网上搜了许多关于Ipad投屏的信息,下面简单说明一下,包括怎么使用! 1.根据在网上搜索的结果, ...
- 解决相关css基础问题
//html代码 <div class="operateWays"> <label> <input type="radio" na ...
- Range Modular Queries
Range Modular Queries 题意 给出一个数列,q个查询,问查询区间内有几个数 a[i] % x == y. 分析 其实裸的分块就能过了,跑的还特别快. 这里分块的作用就是排序. 在x ...
- javaSE_08Java中static、继承、重写
一.Static 学习静态这个关键字,关键是抓住两个点: 1,关注其语法特点 2,关注其使用场景 案例讲解: 我们先从静态变量开始,当一个成员变量加上static修饰之后,会是一个什么效果? 比如创建 ...
- 关于Atlassian无法注册的问题,请看过来
好多童鞋在用团队构建工具git的时候,必然用到git的可视化工具sourceTree来管理项目一些操作,那么当我们下载完sourTree的时候,会有一个选择,已有账户登录还是免费账户,免费账户只有三十 ...