2004年数据库查询优化实例
情况:sqlserver 2000,资源表,记录近30万条。资源有一个整数的id字段,自动增量,但是资源可以被删除。所以,id并不连续。
用.net SqlDataAdapter进行分页查询,由于Fill()方法的机制问题,使得在DataGrid里面进行翻页的时候延时非常大。数据库
服务器和web服务器同在局域网,延时大约有3-4秒。经过分析,对此进行优化。
假设,记录的id是连续的,那么如果每页10条,那么我们要得到第12页,就需要第十一页最后一个记录的id。11 x 10 = 110,这个记录id就是110。所以第12页这么得到,select top 10 * from resource where id>110,这条语句的查询效率是非常高的。
但是如果id不连续,怎么办呢?
这里进行估算。因为cpu进行数值运算的耗时比起数据库查询可以忽略不计。假设,id是连续的,那么先统计一个数字。如果id连续,那么第m页需要的前一个记录id可以这么得到:(m – 1) * 10。所以先统计:
Select count(id) from resource where id<=(m-1)*10
假设统计得到的值为p,p<=(m-1)*10。如果p<(m-1)*10,那么我么可以这样查询:
Select top (((m-1)*10 – p) + 10) * from resource where id>(m-1)*10
查询完毕,取最后的10条记录就可以了。
这种方法对于实际的应用已经足够了。因为,一个几十万条记录的表一般是不经常删除操作的。如果有极端情况,那么可以连续估算2-3次,就可以比较准确了。
也就是(m-1)*10 – p很大的情况下,为了避免查询出太多的记录,进行二次估算。既然p太小了,再次假设id为(m-1)*10后的记录号是连续的。我们需要的id是(m-1)*10 + ((m-1)*10 – p) = 2*(m-1)*10 –p。
查询:
Select count(id) from resource where id<=2*(m-1)*10 –p
得到q,那么我们真正需要的查询是:
Select top (2*(m-1)*10 –p – q+ 10) * from resource where id>2*(m-1)*10 –p
取查询结果的最后10条记录。
这种优化可以用存储过程来实现,获得更好的效果。
经过这样的优化以后,查询速度从原来的超过3秒多变成了瞬间,不足1秒,当时尚未使用存储过程。这是在asp.net 1.1的时候,利用DataGrid绑定数据的时候解决sqlserver 2000查询效率的一个实例。在此提供出来只是提供一个思路,方案也许有用,也许已经过时了。