小弟在编一个查询数据库信息的类,原先的SQL语句是一个union查询,即把很多的select语句用union标识符连接起来,以便可以一次性从数据库检索到信息。不过由于数据量太大,union查询要很长时间才出结果,因而网页上面显示查询到的数据也要等待很长时间。于是我打算把每个查询放到一个线程中去跑,但是最终出来查询结果的总时间和用union查询出来的总时间差不多,我想用线程查询的话结果应该会快一点。不知道是不是代码写的有问题,还是oracle数据库会对从一台机子过来的查询请求进行排队。希望各位老大指点一二。代码如下:
try{
catchConn(); //得到数据库连接
outputList=new Vector();
outputArrayList=new ArrayList();
class Query implements Runnable {
private String innersql;
Thread t; private Thread gett(){
return t;
} public Query(String sqls){
innersql=sqls;
t=new Thread(this);
t.start();
}
public void run(){
try{
Statement innerstmt = dbConn.createStatement (java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE,java.sql.ResultSet.CONCUR_READ_ONLY);
ResultSet innerrs = innerstmt.executeQuery(innersql);
while (innerrs.next()){
Hashtable outputInfoList = new Hashtable();
outputInfoList.put("name",innerrs.getString(1));
outputInfoList.put("area",innerrs.getString(2));
outputInfoList.put("count",new Integer(innerrs.getInt(3)));
System.out.println(innerrs.getString(1)+innerrs.getString(2)+" "+innerrs.getString(3));
outputArrayList.add(outputInfoList);
}
innerrs.close();
innerstmt.close();
}
catch(Exception e1){
System.out.println("error");
}
}
}
Query a1=new Query(sqllist[0]);
//sqllist是7个长度的一维数组,每一个单位里面放一条查询语句,就是原来准备用union查询来合并的查询语句
Query a2=new Query(sqllist[1]);
Query a3=new Query(sqllist[2]);
Query a4=new Query(sqllist[3]);
Query a5=new Query(sqllist[4]);
Query a6=new Query(sqllist[5]);
Query a7=new Query(sqllist[6]);
try{
a1.gett().join();
a2.gett().join();
a3.gett().join();
a4.gett().join();
a5.gett().join();
a6.gett().join();
a7.gett().join();
}
catch(Exception e){
}
接下来的语句不贴了,就是等到所有线程运行完毕后,把查询结果从ArrayList取出来,显示在网页上。
try{
catchConn(); //得到数据库连接
outputList=new Vector();
outputArrayList=new ArrayList();
class Query implements Runnable {
private String innersql;
Thread t; private Thread gett(){
return t;
} public Query(String sqls){
innersql=sqls;
t=new Thread(this);
t.start();
}
public void run(){
try{
Statement innerstmt = dbConn.createStatement (java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE,java.sql.ResultSet.CONCUR_READ_ONLY);
ResultSet innerrs = innerstmt.executeQuery(innersql);
while (innerrs.next()){
Hashtable outputInfoList = new Hashtable();
outputInfoList.put("name",innerrs.getString(1));
outputInfoList.put("area",innerrs.getString(2));
outputInfoList.put("count",new Integer(innerrs.getInt(3)));
System.out.println(innerrs.getString(1)+innerrs.getString(2)+" "+innerrs.getString(3));
outputArrayList.add(outputInfoList);
}
innerrs.close();
innerstmt.close();
}
catch(Exception e1){
System.out.println("error");
}
}
}
Query a1=new Query(sqllist[0]);
//sqllist是7个长度的一维数组,每一个单位里面放一条查询语句,就是原来准备用union查询来合并的查询语句
Query a2=new Query(sqllist[1]);
Query a3=new Query(sqllist[2]);
Query a4=new Query(sqllist[3]);
Query a5=new Query(sqllist[4]);
Query a6=new Query(sqllist[5]);
Query a7=new Query(sqllist[6]);
try{
a1.gett().join();
a2.gett().join();
a3.gett().join();
a4.gett().join();
a5.gett().join();
a6.gett().join();
a7.gett().join();
}
catch(Exception e){
}
接下来的语句不贴了,就是等到所有线程运行完毕后,把查询结果从ArrayList取出来,显示在网页上。
我还是没明白你的意思,有没有什么资料让我看看,我想一个查询完毕后,它的结果集就会返回,难道是等到所有查询线程查询完毕再把结果集返回?
行锁定是什么意思,有没有介绍资料?我试了一下,如果两个select语句同时并发查询一个表的话,会比单个select语句执行出来结果要慢,说明同时查询一个表会影响查询效果,但是比两个select语句分开顺序查询时间要快,说明并发是有效的。我并非要做到查询效果很高效,只不过想速度稍微快一点,也不需要什么数据库服务器端编程,这个是单位里面用来查询数据用。
来自:yanyandt2, 时间:2005-4-27 21:16:42, ID:3059377
你用数据库连接池试试看?
来自:xiaqiapeng, 时间:2005-4-27 21:36:47, ID:3059389 | 编辑
to yanyandt2:
连接池我没用过,是不是把几个数据库连接放到一个vector里面,然后要用的时候取出一个去查询还是把几个查询线程放到一个vector里面,然后要用的时候拿出一个来查询?我有点忘了,这个对我来说有点难。
来自:xiaqiapeng, 时间:2005-4-27 22:43:45, ID:3059478 | 编辑
快来救人啊
来自:xiaqiapeng, 时间:2005-4-28 8:06:27, ID:3059594 | 编辑
今天总有人来解答了吧
来自:yanyandt2, 时间:2005-4-28 15:32:28, ID:3060219
啊,连接池就是在服务器端配置的管理数据库连接的,
welogic,tomcat里都能配置
来自:lover402, 时间:2005-4-28 16:08:59, ID:3060272
晕倒!web请求方式是一应一答,发送HTTP请求,想要返回查询结果,必然是要等待的!!
这和你用不用线程有什么关系??再说了,servlet本身就支持多线程方式
来自:xiaqiapeng, 时间:2005-4-28 22:12:44, ID:3060575 | 编辑
我的意思是想把union查询里面的7个select语句拆开放到7个线程中去跑,按照理论,出来的查询结果应该比union查询出来的结果快,但是事与愿违,出来结果的时间和union查询出来的时间一样,我就感到不能理解.
来自:yanyandt2, 时间:2005-4-28 23:16:03, ID:3060605
你虽然用了7个线程,但是数据库连接还是一个,所以时间就一样了。
来自:wpx, 时间:2005-4-29 12:20:25, ID:3060626
把你要连接的表先写个VIEW,然后在VIEW里查试试
来自:yangxiao_jiang, 时间:2005-4-29 16:12:20, ID:3060899
wpx说的对,你可以建立视图,或者写存储过程,这样应该能快一些
而且,你查询用不用线程都是一样的。楼上的都说了,用连接池只能去掉连接数据库的开销,查询的时间是少不了得。
来自:lares, 时间:2005-4-29 16:26:42, ID:3060916
用多线程不会加快速度的,用union快
来自:kusanagi, 时间:2005-4-29 17:18:47, ID:3061016
//用多线程不会加快速度的,用union快
严重表示同意,多线程会使速度更慢。
你把代码贴出来看看。
如果能不用union的话会快一些,用了也就是7次查询时间+1次连接数据库时间
来自:xiaqiapeng, 时间:2005-4-30 0:20:47, ID:3061278 | 编辑
to yanyandt2:
引用:" 来自:yanyandt2, 时间:2005-4-28 23:16:03, ID:3060605
你虽然用了7个线程,但是数据库连接还是一个,所以时间就一样了。 "
什么意思??如果多几个数据库连接,速度会快?!各位老大,我其实也是想试试多线程能否奏效,我刚在学,拜托![:D]
来自:xiaqiapeng, 时间:2005-4-30 0:08:31, ID:3061282 | 编辑
我知道union的时间和一次一次查的时间差不多,这个贴子想讨论的就是为何用7个线程查询出来的时间和union查询出来的时间差不多,请往这方面讨论.yanyandt2已经点到了一点,各位知情的能否再深入探讨一下,本人也是个学习JAVA的新手,想做深入的了解.[:D]
来自:xiaqiapeng, 时间:2005-4-30 0:19:34, ID:3061292 | 编辑
好了,说的再具体一点吧,这个贴子就是讨论本例中多线程的功效,我对我的union查询做了测试,运行一次要14秒(最近的一次竟然运行了36秒,数据库业务忙的时候),单个select子查询要2秒(有7个这样的子查询),我原先考虑的是我大概能在3-4秒出结果(不管我预测是否对还是错,因为具体的调度策略我不知道,但是也应该比14秒要快吧?!),结果出来的还是和union查询一样的时间,我就是这点不明白,大家讨论讨论吧,暂不考虑服务器端编程的问题,当然也欢迎大家谈[:D]
来自:yanyandt2, 时间:2005-4-30 9:17:37, ID:3061412
你用了多线程,其实线程是开在了java虚拟机中,而7个线程都用了一个数据库连接,
所以总的来说,你在数据库端的访问还是 1 个“通道”。
我是建议你每个线程使用不同的连接,再试试。
问题讨论没有结束 ...
你的多线程共享一个connection,而一个connection链接一个数据库,当然一次只能执行一条SQL语句,这和没有多线程的效率是一样的,你程序的瓶颈在connection。
建议你把线程类从方法中拿出来,单独定义。
多线程提高的只是cpu利用率。比如单线程占用10%CPU资源。那么拥有7线程的进程相当于占用了70%的cpu资源。
但是你如果每个线程里进行数据库查询。数据库执行查询时内部进行复杂的计算占用90%的的cpu资源,那么就没有多少cpu资源可用了。怎么会有效率的提高呢?
多线程只是在cpu空闲时有用!
用view是没多大用的(少了sql语句编译的一点点时间),用存储过程更是瞎扯。union的效率绝对比多线程高。
想要再提高效率,只能在SQL语句本身进行优化,或者想办法不用union.
楼上所说的每线程都开一个数据库连接的方式也许可以,不知道数据库内部如何处理,不敢妄加评论
---------------------------------------------------------------------------来自:xiaqiapeng, 时间:2005-4-30 10:10:45, ID:3061470 | 编辑
好的
来自:xiaqiapeng, 时间:2005-4-30 13:51:27, ID:3061682 | 编辑
试了一下,还是老样(14秒),而且控制台输出是到14秒的时候一下子都出来的,而不是随着时间交替输出,感觉还是没有并发,以下是修改后的代码:
private Connection getConn(){
try {
Context initCtx = new InitialContext();
Context ctx = (Context) initCtx.lookup("java:comp/env"); //获取连接池对象
Object obj = (Object) ctx.lookup("jdbc/OracleDB"); //类型转换
javax.sql.DataSource ds = (javax.sql.DataSource) obj;
return ds.getConnection();
}
catch (Exception sqle) {
System.out.println("cannot connect db inside getConn");
return null;
}
} class Query implements Runnable {
private String innersql;
Thread t;
private Thread gett(){
return t;
}
public Query(String sqls){
innersql=sqls;
t=new Thread(this);
t.start();
}
public void run(){
try{
Connection innerconn=getConn();
Statement innerstmt = innerconn.createStatement (java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE,java.sql.ResultSet.CONCUR_READ_ONLY);
ResultSet innerrs = innerstmt.executeQuery(innersql);
while (innerrs.next()){
Hashtable outputInfoList = new Hashtable();
outputInfoList.put("name",innerrs.getString(1));
outputInfoList.put("area",innerrs.getString(2));
outputInfoList.put("count",new Integer(innerrs.getInt(3)));
System.out.println(innerrs.getString(1)+innerrs.getString(2)+" "+innerrs.getString(3));
outputArrayList.add(outputInfoList);
}
innerrs.close();
innerstmt.close();
innerconn.close();
}
catch(Exception e1){
System.out.println("error");
}
}
}
以下是配置:
C:\Tomcat 4.1\conf\server.xml
<!-- Tomcat Venture Context -->
<Context path="/venture" docBase="venture" debug="0">
<Resource name="jdbc/OracleDB" auth="Container"
type="javax.sql.DataSource"/>
<ResourceParams name="jdbc/OracleDB">
<parameter>
<name>factory</name>
<value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
</parameter>
<parameter>
<name>driverClassName</name>
<value>oracle.jdbc.driver.OracleDriver</value>
</parameter>
<parameter>
<name>url</name>
<value>jdbc:oracle:thin:@130.37.0.1:1521:oranb</value>
</parameter>
<parameter>
<name>username</name>
<value>test</value>
</parameter>
<parameter>
<name>password</name>
<value>test</value>
</parameter>
<parameter>
<name>maxActive</name>
<value>20</value>
</parameter>
<parameter>
<name>maxIdle</name>
<value>10</value>
</parameter>
<parameter>
<name>maxWait</name>
<value>5000</value>
</parameter>
</ResourceParams>
</Context>
[:D]
来自:xiaqiapeng, 时间:2005-4-30 13:33:13, ID:3061690 | 编辑
我只修改了线程类,加了个得到数据库连接的方法,就是每次建立一个新的数据库连接,先试试,也不搞复杂的连接池了,其他和原来一样。[:D]
问题讨论没有结束 ...
http://www.delphibbs.com/delphibbs/dispq.asp?lid=3059373
union
select 'b112',area,count(*) from venture.userinfo where yhlb='KG' and logintype<>'KH120' and to_char(logdt,'YYYYMMDD') between '19900101' and '20050327' group by area
union
select 'c174',area,count(*) from venture.userinfo where yhlb='DG' and logintype<>'KH113' and to_char(logdt,'YYYYMMDD') between '19900101' and '20050327' group by area
union
select 'd027',area,count(*) from venture.userinfo where (yhlb='XH' or yhlb='XE') and logintype<>'KH119' and to_char(logdt,'YYYYMMDD') between '19900101' and '20050327' group by area
union
select 'e034',area,count(*) from venture.userinfo where yhlb='ZH' and logintype<>'KH120' and to_char(logdt,'YYYYMMDD') between '19900101' and '20050327' group by area
union
select 'f103',area,count(*) from venture.userinfo where yhlb='KG' and yhlb2='LYH' and logintype<>'KH120' and to_char(logdt,'YYYYMMDD') between '19900101' and '20050327' group by area
union
select 'g010',area,count(*) from venture.userinfo where yhlb='XM' and yhlb2='LYH' and logintype<>'KH119' and to_char(logdt,'YYYYMMDD') between '19900101' and '20050327' group by area;
select
case when (yhlb='CA' or yhlb='CE') and logintype<>'KH121' then 'a887'
when yhlb='KG' and logintype<>'KH120' then 'b112'
when yhlb='DG' and logintype<>'KH113' then 'c174'
else ......
end case as field1
,area from venture.userinfo
where to_char(logdt,'YYYYMMDD') between '19900101' and '20050327'
) as temptable
group by field1,area
早贴出来不久结了嘛,一个sql搞定
7个union相当于内部查询7次然后汇总成结果集。这个sql是我按sqlserver2000的写法写的。
你看看oracle中case的写法和子查询的写法。另外to_char(logdt,'YYYYMMDD') between '19900101' and '20050327'也是一个效率低下的原因
如果你对logdt作了索引,这种写法是不会利用到索引检索的。因为你对该字段进行了一次计算再比较。如果把'19900101'改成日期类型用大于小于符号比较就能提高效率。
完毕!
select 'a887',area,count(*) from venture.userinfo where (yhlb='CA' or yhlb='CE') and logintype<>'KH121' and logdt between to_date('19900101','YYYYMMDD') and to_date('20050327','YYYYMMDD') group by area
每个子查询2秒=0.5秒建立连接+1.5秒进行查询。
1.5秒进行查询这个事件是一个大计算量任务,cpu没有空闲(不能切换到其它线程或切换后也没有意义)。
7个连接的最好情况是0.5+1.5*7=11秒,这是建立在所有建立连接的工作并行完成的前提下。
多线程在进行多个查询时(多个1.5秒的计算任务可能会有并行,但由于是大计算量任务并行也无法更高的提高cpu利用率来提高速度,而提高cpu利用率是多线程提速的途径)时可能有些优势,但在多次建立连接的开销又把它抹平了。