用临时表改善数据查询的性能

1.  所解决的问题的特征(同时具备)

a)  查询的SQL执行速度慢(因表大、业务逻辑导致查询本身复杂低效等因素,一次查询耗时长,可达分钟数量级)

b)  查询结果数据量大(例如数10万行数量级)

c)  如果分页查询,每页耗时与一次性查询耗时相当


2.   问题的难点

a) 由于结果数量大,一次性查询或分少量几页查询会导致服务器内存消耗过多,无法正常工作。似乎必须分很多页获取数据。

b) 由于每页查询耗时长,分几十页查询会导致总时间比一次性查询增长几十倍,不可接受。

c) 由于过程较长,分页查询的中途源数据发生变化(查询的主表插入或删除数据)的概率增加了。如果源数据发生变化,还会在结果中出现遗漏(删除数据导致)和重复数据(插入数据导致)

3.   解决的方法与思路

a) 将查询结果放入数据库内实时创建的临时表(Create table TMP_xxxx as <查询SQL>)

b) 分多页(可达数百页)查询临时表,查询完后删除临时表。由于对临时表的简单查询(只是select * from TMP_xxxx)速度很快,多页累计速度下降在可接受范围。

c) 由于每页数据量小(如2000行),内存占用量很小。

d) 与固定的中间表机制相比,此方法可避免相关表结构变化与固定中间表结构的不兼容问题。

e) 由于临时表是一次性查询生成的,不会出现数据遗漏或重复问题。


4.   实现的例子

a)  签约方账单全表下载:

CsPayNotAction.java中

publicString readyDownAllNatiPayNotDataList(){

       //…预备csNatiOiDet和pages参数值

       //数据处理工具类,将数据写入Excel

IResultPageHandler pageHandler = new XLSResultPageHandler(fileName, bum);

//将工具类实例传给DAO,由DAO完成临时表的创建、查询、删除

csPayNotTempletService.prepareNatiPayNotDetFullListDownload(csNatiOiDet,pages,pageHandler);

 

}

b)  AbstractBaseDAO.fetchDataUsingTmpTable()是通用工具方法,可以对给定的SQL一步做到一次性完成运行SQL,建临时表存储结果数据,分页从临时表取数据,发送数据给resultHandler,及删除临时表的过程,条件是临时表的数据为最终结果,无需再转换加工。参考该方法的实现,可了解几个更基本的通用工具方法。


5.   解决的效果

签约方账单全表下载,55万行结果,查询并建临时表耗时6分钟,每页2000行获取数据并写入excel,共耗时约9分钟。下载总共耗时约15分钟。


6.   进一步扩展应用

现已发现有的复杂SQL查询(如雇员基本情况表下载)可分成两步来把速度加快10倍左右:将第一步结果记入中间表,在对中间表进行定制的SQL查询,最后删除临时表。尚未实现。


6.   副作用

如果建临时表后,程序没来得及删除就将服务器停掉,将需要另外的机制来删除该临时表


本文作者:范强

       2015.12.22 


你可能感兴趣的:(用临时表改善数据查询的性能)