SQL Server性能优化(5)表设计时的注意事项

一、 是否需要冗余列

现在一些项目的数据库设计中,为了提高查询速度,把基本表的一些列也放到了数据表里,导致数据冗余。例如在热表的数据库里,原始数据表Measure_Heat里加了如房间号,单元号,楼号,小区,户主姓名,户主编号等列。以下分析其性能。

测试步骤:

1. 建立相同的表(不包含冗余列,如房间号,单元号,楼号,小区,户主姓名,户主编号,冗余列从Measure_Cjd内Join获取)两个表索引相同。

2. 把Measure_Heat里的数据原封不动插入到新表内,共5326375行

SELECT [id]
      ,[表地址]
      ,[上次抄表热量]
      ,[当前热量]
      ,[热功率]
      ,[瞬时流量]
      ,[累计流量]
      ,[供水温度]
      ,[回水温度]
      ,[温差]
      ,[累计工作时间]
      ,[实时时间]
      ,[采集时间]
      ,[单价]
      ,[通讯状态]      
      ,[室温]
      ,[设定室温]
      ,[阀门状态]
  INTO [HeatMeasure_Weifang].[dbo].[Measure_heat_test]
  FROM [HeatMeasure_Weifang].[dbo].[Measure_heat]

测试项

1. 查看两个表占用硬盘大小

原表:大小1260M

image

新表:915M(缩小比例为(1260-915)/1260= 0.274,也就是缩小了超过四分之一的大小

image

2. 查询性能

a. 查询前清除缓存

--查询旧表
DBCC DROPCLEANBUFFERS    --关闭缓存,从缓冲池中删除所有缓冲区
DBCC FREEPROCCACHE        --关闭缓存,从过程缓冲区删除所有元素
select top 10 * from Measure_heat

结果:

clipboard

--查询新表
DBCC DROPCLEANBUFFERS    --关闭缓存,从缓冲池中删除所有缓冲区
DBCC FREEPROCCACHE        --关闭缓存,从过程缓冲区删除所有元素
select top 10 a.*, 
b.社区编号,b.楼房编号,b.楼层,b.单元编号,b.房间号, b.户主编号,b.户主姓名 
from Measure_heat_Test a left join measure_cjd b 
on a.表地址=b.表地址

clipboard[4]

可见,冗余列在查询时(清空数据库缓存的情况下),的确会提高查询速度(63毫秒VS911毫秒

b. 不清除缓存,原表0毫秒

image

新表:13毫秒

image

3. 插入性能(插入一万条数据批量)

旧表:

insert into Measure_heat
select top 10000 [表地址]
           ,[上次抄表热量]
           ,[当前热量]
           ,[热功率]
           ,[瞬时流量]
           ,[累计流量]
           ,[供水温度]
           ,[回水温度]
           ,[温差]
           ,[累计工作时间]
           ,[实时时间]
           ,[采集时间]
           ,[单价]
           ,[通讯状态]
           ,[社区编号]
           ,[楼房编号]
           ,[楼层]
           ,[单元编号]
           ,[房间号]
           ,[户主编号]
           ,[户主姓名]
           ,[室温]
           ,[设定室温]
           ,[阀门状态]
 from Measure_heat

image

新表

insert into Measure_heat_Test
select top 10000 [表地址]
      ,[上次抄表热量]
      ,[当前热量]
      ,[热功率]
      ,[瞬时流量]
      ,[累计流量]
      ,[供水温度]
      ,[回水温度]
      ,[温差]
      ,[累计工作时间]
      ,[实时时间]
      ,[采集时间]
      ,[单价]
      ,[通讯状态]      
      ,[室温]
      ,[设定室温]
      ,[阀门状态]
 from Measure_heat_Test

image

结论:

a. 数据冗余对于查询单表速度是有很大优势的,是多表join的速度的10倍以上,性能不是一个数量级。道理也可以理解,多表join是会扫描多个表,性能肯定有损耗。

b. 除了性能优势,包含冗余列在数据存储空间方面多了27%的硬盘空间。

c. 插入性能,同时插入1w条数据,都在500ms左右,差别不大。

d. 如果把上图Measure_cjd的基本数据,到到缓存内,新表查询应该会有比原表更高的性能。

二、列的类型和范围,比如一些范围小的属性int字段尽量用smallint 或者tinyint,节省磁盘空间和数据跨页的可能行。

image

比如一下几列,都可以用smallint

image

节省空间(节省空间(1327-1152)/1327=0.132,也就是节约了10%的空间)

image

image

统计使用页数,参考(http://www.cnblogs.com/zping/archive/2010/12/20/1911406.html

SELECT Object_name(i.object_id)          AS objectName,
       i.[name]                          AS indexName,
       Sum(a.total_pages)                AS totalPages,
       Sum(a.used_pages)                 AS usedPages,
       Sum(a.data_pages)                 AS dataPages,
       ( Sum(a.total_pages) * 8 ) / 1024 AS totalSpaceMB,
       ( Sum(a.used_pages) * 8 ) / 1024  AS usedSpaceMB,
       ( Sum(a.data_pages) * 8 ) / 1024  AS dataSpaceMB
FROM   sys.indexes i
       INNER JOIN sys.partitions p
               ON i.object_id = p.object_id
                  AND i.index_id = p.index_id
       INNER JOIN sys.allocation_units a
               ON p.partition_id = a.container_id
WHERE  i.object_id = Object_id('dbo.Measure_heat')
       AND i.index_id <= 1
GROUP  BY i.object_id,
          i.index_id,
          i.[name]

image

结论,虽然数据行数相同,但是页数减少了。

三、尽量不要允许NULL,除非必要,可以用NOT NULL+DEFAULT代替。

如性别

CREATE TABLE "dbo"."Test"    
(    
    id int PRIMARY KEY,    
    sex bit DEFAULT (1),    
    name varchar(40),    
    age int DEFAULT ((1)),    
)
posted @ 2015-05-20 08:56  悉路  阅读(734)  评论(0编辑  收藏  举报