image类型被SqlServe定义为大对象数据类型。为了减少行溢出带来的性能影响,SqlServer数据库对于大对象数据类型会采取特殊的管理方法,它会将这个数据与普通数据分开管理。现在 我们需要观察一下随着数据库文件的增长, 我们的image类型会给我们的数据库查询造成怎样的困扰。
Tsoft数据库分别设计有 imgTable1(主键,聚集索引),imgTable2(没有建立任何索引) ,imageInfo(图片明细表), intTable1(用于增大数据库空间), intTable2(用于增大数据库空间)
数据库建表脚本如下:
用于查询的两个表如下,其余表主要用于增大数据库文件的占有空间。
图片数据存储主表imgTable1
Id |
varchar |
主键 |
图片ID |
img |
image |
|
图片文件 |
type |
varchar |
|
图片类型 |
leng |
varchar |
|
图片大小 |
ts |
datetime |
|
存储时间 |
图片信息表imageInfo
ImageID |
varchar |
图片ID |
ImageName |
varchar |
图片名称 |
ImageSize |
varchar |
图片大小 |
ImageDescription |
varchar |
描述 |
ImageType |
varchar |
图片类型 |
ImageFile |
varchar |
图片路径 |
ImageOrder |
int |
存储顺序 |
ts |
datetime |
存储时间 |
数据插入采取循环插入, 每次插入顺序为 intTable1(1条), imgTable1(1条),imgTable2(1条) ,intTable2(1条), imageInfo(5条)
这样便于模仿真实业务情况,避免对目标表实行连续插入数据。
执行插入数据的Sql语句如下:
注: 为避免用户将图片存储在行记录上,我们将text in row 关闭。
查询结果均为100条目标数据。
查询时间的获取方式:
declare @StratDate datetime
declare @Endtime datetime
set @StratDate=getdate();
---- 测试的sql语句
set @Endtime=getdate()
select datediff(millisecond,@stratDate,@Endtime)
每次查询前清除高速缓存:
DBCC FREEPROCCACHE
DBCC DROPCLEANBUFFERS
每个执行语句查询次数3次,结果取平均数。
软件: SqlServer2000
硬件:Cup Inter(R) Core(TM) Duo CPU E7500 2.93G
内存:3G
硬盘:500G
(图1)
如图中a 曲线执行的sql语句是
select * from imageInfo where ImageSize='269728' and imageorder=2
(单独查询数据表imageInfo)
b曲线执行的sql语句是
select b.* from ImgTable1 a left join ImageInfo b on a.id=b.ImageID where a.leng='269728' and b.ImageOrder=2
(对数据表ImageInfo和ImgTable1做表联合,其中ImgTable1含有img类型的存储数据)
为了使实验更加准确,我们预先设定的两个sql语句查询出的结果数据完全相同(列,条数及每条的明细均相同),根据图中的执行曲线可以看出随着数据库的增加,查询时间不断上升,当数据库接近100G的,查询时间已经接近1250ms,但是a ,b曲线一直比较接近,说明ImgTable1图片表并未对普通表imageInfo造成什么影响。
(关于查询时间随数据库上升比较快是否是碎片影响将另作分析)
(图2)
如上图 其中 a b曲线如图1所示Sql语句
曲线c 对应执行的查询语句
select * from ImgTable1 where leng='269728'
(单独查询图片所在的表,显示ImgTable1所有列的数据)
曲线d 对应执行的查询语句
select a.* from ImgTable1 a left join ImageInfo b on a.id=b.ImageID where a.leng='269728' and b.ImageOrder=2
(和不含图片存储表做联合表查询,显示ImgTable1所有列的数据)
曲线e对应执行的查询语句
select * from ImgTable1 a left join ImageInfo b on a.id=b.ImageID where a.leng='269728' and b.ImageOrder=2
(和不含图片存储表做联合表查询,显示ImgTable1的数据和 ImageInfo的所有列)
其中 c和d 曲线查询的数据完全相同为ImgTable1所有列的数据,e曲线查询结果多出ImageInfo的所有列的数据。
如图可知: 随着数据库的空间不断增加,和普通表做表联合查询后不会对含图片的查询造成很大影响,含图片的表查询本身已经消耗了将近10s的时间,并随着数据库的增大查询时间不断增大。然而在查询逻辑如此简单的情况下100条的数据为什么会有如此大的时间消耗呢,我们继续关注下面的场景。
(图3)
执行Sql语句
select top 条数(横坐标) * from ImgTable1 where leng='269728'
横坐标表示top 的条数,纵坐标指耗费的时间。
在数据大小不变的情况此图说明
显示的查询时间随显示的条数增加而增加,几乎成直线,说明由于每条数据都含有图片,每条记录占有比较多的page,数据库的查询时间主要消耗在数据读取和输出上面。
综上所述:在100G之内图片的存储,并没有给数据库表的查询带来我们无法预料的影响,只是大对象(图片)本身的输出可能是查询过程的主要的影响因子。
据查询有关资料,这是因为数据表对于大对象的存储只是在记录行写入了对象所在页的索引,对象真正存储在其它页面上,所以只有涉及到图片列的读取时大会产生查询效率影响,如果不显示此图片列,做相关的表联合查询则几乎不受影响。
当然本实验虽然模拟真实的数据插入(会产生碎片),但并没有关注碎片给查询带来的影响。如果有需要可以进一步进行讨论。