这样的sql合理么

[复制链接]
查看11 | 回复9 | 2010-9-3 12:44:53 | 显示全部楼层 |阅读模式
今天写了一条sql语句,返回结果集为300行,一致读大于70w,不过整个查询能在5秒内执行完。
语句涉及到三个表:a,b,c。
关系类似:
a 和b的关系1对n;
a和c的关系1对m;
b的n条记录根据c的m条记录生成;
正常情况下m=n。
现在要求是找到a中的记录:
满足1:b中与其对应的只有一条记录且一列为固定值。
2:c中与其对应的有m(m>1)条记录。
a大概100w数据;b有1000w的数据量,c数据量比较小,主要是写入b时的参照
select * from a where

(select count(x) from b where b.x=a.x and b.xx=a.xx and b.xxx='sdfsd')=1 ---保证固定列存在在b中

and (select count(y) from c where c.y=a.y and c.yy=a.yy)>1
---保证c中对应的行数大于1

and ( (select count(x) from b where b.x=a.x and b.xx=a.xx )=1;
---保证b中只有一行记录
这样的语句写出来,逻辑读有70w+,实在是汗颜啊。
问:一、请教有什么好的方法实现这个功能么?
二、pga的hash区自动调整有什么限制范围(见注2)?
三、如果逻辑读大的sql,执行时间不是很长的话(如本例),会给系统带来很大压力么?
注:1)如果写成联合查询一致读可以降到10w一下,但是开发工具限制只能修改where后面的部分。
2)如果把pga设成手动,把hash_area_size设置成100000000(系统现为默认自动调整),一致读降到了20W左右。
3)连接的字段不是索引就是主键列。




test.sql(93.8 KB, 下载次数: 6)2010-11-18 19:59 上传点击文件名下载附件




test_sql2.rar(4.67 KB, 下载次数: 4)2010-11-18 19:59 上传点击文件名下载附件

[ 本帖最后由 hotdog04 于 2010-11-18 20:01 编辑 ]
回复

使用道具 举报

千问 | 2010-9-3 12:44:53 | 显示全部楼层
把相关子查询改为表连接。但你又说有限制,那么这是个很糟糕的开发工具。
第1,3个条件可以合并为一个:
(select count(x)||MAX(b.xxx) from b where b.x=a.x and b.xx=a.xx)='1sdfsd' ---保证固定列存在在b中并且只有一行记录
回复

使用道具 举报

千问 | 2010-9-3 12:44:53 | 显示全部楼层
好奇怪的开发工具.
回复

使用道具 举报

千问 | 2010-9-3 12:44:53 | 显示全部楼层
谢谢,测了一下,修改后,逻辑读降到了60w。
随便更正一下,不是开发工具不强力,因为我是修改别人的程序,
他在程序里把前半截写死了。。
回复

使用道具 举报

千问 | 2010-9-3 12:44:53 | 显示全部楼层
我就有遇到有的报表工具有改SQL的坏毛病。。。为了让工具能把SQL改完之后依然正确,我也得绕着弯子把SQL写的很麻烦
回复

使用道具 举报

千问 | 2010-9-3 12:44:53 | 显示全部楼层
如果已有程序的没有限制,怎么写高效的语句呢?
回复

使用道具 举报

千问 | 2010-9-3 12:44:53 | 显示全部楼层
原帖由 hotdog04 于 2010-11-16 16:41 发表
如果已有程序的没有限制,怎么写高效的语句呢?


LZ, 你测试一下如下的语句!

select *
from a
where exists(select 1

from b

where b.x = a.x

and b.xx = a.xx

and b.xxx = 'sdfsd'

having count(*) = 1)
and exists(select 1

from c

where c.y = a.y

and c.yy = a.yy

having count(*) > 1);


回复

使用道具 举报

千问 | 2010-9-3 12:44:53 | 显示全部楼层
好,明天测测
回复

使用道具 举报

千问 | 2010-9-3 12:44:53 | 显示全部楼层
可以试试这些方法:
select *
from a
where exists(select 1

from b

where b.x = a.x

and b.xx = a.xx

having count(*) = 1

AND MAX(b.xxx )= 'sdfsd')
and exists(select 1

from c

where c.y = a.y

and c.yy = a.yy

having count(*) > 1);

EXISTS 改为连接:
select a.*
from a
,(select a.ROWID ROWID_2

from b,a
where b.x = a.x
and b.xx = a.xx
GROUP BY a.ROWID
having count(*) = 1

AND MAX(b.xxx )= 'sdfsd'
) a2
,(select a.ROWID ROWID_3
from c,a
where c.y = a.y

and c.yy = a.yy
GROUP BY a.ROWID
having count(*) > 1
) a3
WHERE a.ROWID = a2.ROWID_2 AND a.ROWID = a3.ROWID_3

或者:

select a.*
from a
,(select b.x,b.xx

from b
GROUP BY b.x,b.xx
having count(*) = 1

AND MAX(b.xxx )= 'sdfsd'
) a2
,(select c.y,c.yy
from c
GROUP BY c.y,c.yy
having count(*) > 1
) a3
WHERE a.x=a2.x AND a.xx=a2.xx
AND a.y=a3.y AND a.yy=a3.yy

或者上述方法的混合,看看哪个效果最好。
回复

使用道具 举报

千问 | 2010-9-3 12:44:53 | 显示全部楼层
测试结果很纠结啊,
使用子查询的逻辑读都很大60W+,速度却快3s多;
使用连接查询的逻辑读比较小10W+,速度却慢8s多;
到底怎么取舍呢?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题

0

回帖

4882万

积分

论坛元老

Rank: 8Rank: 8

积分
48824836
热门排行