Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1634496
  • 博文数量: 201
  • 博客积分: 2812
  • 博客等级: 少校
  • 技术积分: 3029
  • 用 户 组: 普通用户
  • 注册时间: 2011-01-18 18:28
个人简介

从事数据库工作多年,目前看好分布式NeSQL/HTAP数据库在企业客户市场的发展。未来的主要方向是——致力于 NewSQL/HTAP 数据库的推广普及。

文章存档

2016年(1)

2015年(8)

2014年(23)

2013年(50)

2012年(32)

2011年(87)

分类: Sybase

2011-04-22 09:21:14

   近日遇到一个SQL调优问题:用户的一个应用为了实现IQ数据结果集的分页,写了一个查询,用来对一个有4千多万记录的表中返回一百六十多万记录的结果集进行分页(每页100条记录)。取一页数据大约20秒左右,用户觉得太慢了。
   出于保密的考虑,这里用tpchdb(我的博文中有多其的详细描述)来模拟问题和相应查询,然后跟大家分享对其进行优化的方法。希望能对大家实现类似功能时有所帮助。
 
1. 模拟问题
 
(1) 机器环境
    用于模拟问题的机器配置如下:
        Linux 4core/8G的虚拟机,CPU主频2.5GHZ
    IQ 版本 15.2 ESD#1
    IQ CFG配置: -iqmc=1024  -iqtc=1024
 
(2) 数据库
    采用的是TPCHDB,尺寸10GB。使用表lineitem。
    lineitem表总记录数: 59986052
   
(3) 问题查询
drop view if exists LINEITEM_VIEW;
create  view LINEITEM_VIEW
  as select rowid(lineitem) as idd , *
     from lineitem where 1=1  and l_linestatus = 'F';
SELECT * FROM ( SELECT RANK() OVER (ORDER BY idd ) rowid, * from LINEITEM_VIEW ) AS TMP WHERE TMP.rowid>0 AND TMP.rowid<=100;
   
    说明:使用l_linestatus = 'F'条件后,返回的结果集记录数为: 29998258. 然后对这个结果集进行分页,取出第1页的100条记录。在我的模拟环境下,这个查询执行的时间是113秒!看来是够慢的,比用户的问题查询还要慢不少。
 
2.进行优化
  对这个问题,尝试了几种方法,下面就分别介绍这些方法,最后得出优化的结论。
 
(1) 优化方法1:使用“rowid视图”
    下面是具体的优化实现:
drop view if exists LINEITEM_IDS_VIEW;
create view LINEITEM_IDS_VIEW as select rowid(lineitem) as idd  from lineitem where 1=1 and l_linestatus='F';
SELECT * FROM ( SELECT * FROM ( SELECT RANK() OVER (ORDER BY idd ) as rowid,idd FROM LINEITEM_IDS_VIEW) as TMP WHERE TMP.rowid>0 AND TMP.rowid<=100) A, lineitem B WHERE A.idd=rowid(B) AND B.l_linestatus='F';
 
     采用这个方法,执行时间提高到:15秒!.
     这个方法还可以该为不使用视图,而直接使用原表,具体的查询如下(查询执行时间不变):
SELECT *
FROM (
  SELECT *
  FROM (
       SELECT RANK() OVER (ORDER BY idd ) AS rowid,rowid(lineitem) AS idd 
       FROM lineitem
       WHERE 1=1 AND l_linestatus='F'
  ) AS TMP_IDS
  WHERE TMP_IDS.rowid>0 AND TMP_IDS.rowid<=100
) A, lineitem B
WHERE A.idd=rowid(B) AND 1=1 AND B.l_linestatus='F';
 
      这个方法虽然提升了性能(大概提升了7倍多)感觉还是不够快,能不能进一步提升性能呢?经过尝试答案是可以的,请大家继续往下看。
 
(2) 优化方法2:使用“临时表”
    下面是这个方法的实现:
drop table if exists #table_rowid;
select rowid(lineitem) as rowid into #table_rowid from lineitem where 1=1 and l_linestatus = 'F';
select rowid(a) as rowid, a.rowid as idd, b.* from #table_rowid a,lineitem b where a.rowid = rowid(b) and 1=1 and b.l_linestatus='F' and rowid>0 and rowid<=100;
     采用这个方法,执行时间提高到:7.7秒! 提升了14倍多!
 
  
 
 
 
 
 
 
 
   
阅读(3853) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

eisen2016-07-13 16:39:34

非常有趣的案例,可否请将各个query的plan和timing chart贴出来看看呢?谢谢