怎样玩转千万级别的数据

大数据处理是一个头疼的问题,特别当达不到专业DBA的技术水准时,对一些数据库方面的问题感到无赖。因此仍是有必要了解一些数据库方面的技巧,固然,每一个人都有本身的数据库方面的技巧,只是八仙过海,所用的武功不一样而已。我把我最经常使用的几种方式总结来与你们分享,你们还有更多的数据库设计和优化的技巧,尽可能的追加到评论中,有时一篇完整的博客评论比主题更为精彩。sql

方法1:采用表分区技术。

第一次据说表分区,是之前的一个oracle培训。oracle既然有表分区,就想到mssql是否有表的分区,当时我回家就google了一把,资料仍是有的,在这我儿只是再做一次推广,让更多的人了解和运用这些技术。数据库

表分区,就是将一个数据量比较大的表,用某种方法把数据从物理上分红若干个小表来存储,从逻辑来看仍是一个大表。首先来个结构图:oracle

gdft45bfghty.png

上图虽然不能很清晰的表达表分区的执行过程,可是能够看出表分区要用到那些对象,好比数据文件,文件组,分区方案,分区函数等。数据库设计

咱们以一个用户表(TestUser)为例,假设这个表准备用来存储中国部分公民的数据,每条数据记录着每一个人所属的省份(Area),以及每一个人的姓名(UserName),以下图所示。当数据量达到1千万的时候,查询就比较慢了,这时候的数据优化就迫在眉睫。ide

qqjie_tu_20130911080338.jpg

在优化以前,根据数据的结构,读写操做等,确定会提出若干个解决方案。在这儿就以分区表的方案来优化数据库的查询,这儿以区域来分别存储数据,好比广东的公民存放在AreaFile01.MDF文件中,湖南的公民存放在AreaFile02.MDF的文件中,四川的公民存放在AreaFile03.MDF的文件中,以此类推其它省份,为了实现这个功能咱们就得作分区方案。在作分区方案时,首先要搞清楚分区方案要涉及到的四个对象:文件组,文件,分区函数,分区方案。函数

a:文件组,用来组织数据文件(.MDF)的一个虚拟名称,一个文件组能够添加多个数据文件(.MDF)。打开SQL管理器,找到具体的数据库,而后右键【属性】,进入到【文件组】选项卡,添加Area01,Area02,Area03,Area04四个文件组。如图:性能

6j34jfvry6576utyhsdf.png

b:而后选择中【文件】选项卡,添加AreaFile01,AreaFile02,AreaFile03,AreaFile04,AreaFile05,AreaFile06六个数据文件(.MDF),而后指定每一个文件属于那个文件组(一个文件组能够存储多个数据文件),以及这个文件的物理路径。在这儿你们已经看明白了,这些数据文件,就是物理上来分割一个数据表的数据的。也就是说一个表的数据有可能存储在AreaFile01中,也有可能存储在AreaFile02中,只要用某种方法来指定他们的存储规则就好了。大数据

grt456ytdfgfgs.png

c:分区函数,就是指定数据的存储规则。就是告诉SQL,把新增的数据如何分区。建立一个分区函数,能够用下边的SQL语句来实现。优化

?google

1
2
CREATE PARTITION FUNCTION partitionFunArea (nvarchar(50))
AS RANGE Left  FOR VALUES ( '广东' , '湖南' , '四川' )

d:辛苦的建立了文件,又为其指定文件组,还建一个分区函数,目的只有一个,就是为了建立一个分区方案。分区方案能够用如下代码来建立。

?

1
2
3
4
5
6
7
CREATE PARTITION SCHEME partitionSchemeArea
AS PARTITION partitionFunArea
TO (
     Area01,
     Area02,
     Area03,
     Area04)

通过紧张的四步操做,一个分区方案就呈如今咱们的眼前了。接下来的事,就是咱们要怎样来消费这个分区方案。

首先咱们建立一人普通的表,而后给这个表指定一个分区方案。以下代码。

?

1
2
3
4
5
CREATE TABLE TestUser(
     [Id] [ int ] IDENTITY(1,1) NOT NULL ,
     [Area] nvarchar(50),
     [UserName] nvarchar(50)
) ON partitionSchemeArea([Area])

为了能看到效果,再插入一些数据。

?

1
2
3
4
5
6
7
8
9
10
11
INSERT TestUser ([Area],[UserName]) Values ( '四川' , '肖一' );
INSERT TestUser ([Area],[UserName]) Values ( '四川' , '肖二' );
INSERT TestUser ([Area],[UserName]) Values ( '四川' , '肖三' );
INSERT TestUser ([Area],[UserName]) Values ( '四川' , '肖四' );
 
INSERT TestUser ([Area],[UserName]) Values ( '广东' , '张一' );
INSERT TestUser ([Area],[UserName]) Values ( '广东' , '张二' );
INSERT TestUser ([Area],[UserName]) Values ( '广东' , '张三' );
 
INSERT TestUser ([Area],[UserName]) Values ( '湖南' , '杨一' );
INSERT TestUser ([Area],[UserName]) Values ( '湖南' , '杨二' );

查询全部的数据,能够用select * from TestUser; 按分区查询:就用以下方法:

?

1
2
3
4
5
6
select $PARTITION.partitionFunArea([Area]) as 分区编号, count (id) as 记录数
from TestUser group by $PARTITION.partitionFunArea([Area])
select * from TestUser where $PARTITION.partitionFunArea([Area])=1
select * from TestUser where $PARTITION.partitionFunArea([Area])=2
select * from TestUser where $PARTITION.partitionFunArea([Area])=3
select * from TestUser where $PARTITION.partitionFunArea([Area])=4

效果图:

fsdf44444tfgvxdvxc.png

大家看我一个简单的表的分区是否是就已经完成了。呵呵,固然在实际应用中,仅仅掌握这点是不够的,好比在原分区方案上添加一个分区,删除一个分区。

方法2:用xml类型代替主从表设计,从而达到提升查询性能。

优化和提升数据库的性能,是从一个良好的数据库设计开始的。以一个会议预订系统为例,一个预订会议系统包括了会议时间,会议地点,主持人,参与人,知会人,记录者等相关信息。在的TDD,DDD模型主导的时代,在这儿为了更好的想表达我要阐述的问题,仍是以表驱动模型来进行开发。

用户需求:

  a:一个会议可能有多个主持人,虽然这种状况比较少,可是也有可能有。

  b:一个会议有多个参与人,这个不难理解。

  c:一个会议有可能要让某人知晓,这人能够参与或不参与会议,通常为高层。

  d:一个会议有可能有零个或者多个记录者。

  e:一个会议须要远程视频,投影仪,电脑,麦克风等会议设备中的某些设备。

  f:会议预订成功,或者会议时间,会议地点等重要信息修改后,邮件通知与会人员。

常规数据库设计:

  a:建一个Meeting的主表,用于存放会议名称,会议地点,会议时间等的相关信息。

  b:再建一个MeetingUser的表存储主持人,参与人,知会人,记录者。

  c:一样,会议所须要的设备用MeetingDevice表来存储相关的信息。如图:

t54445666778.png

这样的表结构,是比较常规的设计方法,可是在实际应用中,你会发现一些待改进的问题。好比:

  a:在提取一个会议的相关信息时,会链接多个表进行查询。这种查询在很大的程序上影响了数据库性能。

  b:在作修改操做时也够呛的,先修改主表的相关信息,再把主表关联的子表信息所有删除从新插入一次,这样的操做是否够吐血了。固然有人精益求精,会比较修改前和修改后的数据,再用增长,删除,修改的手段达到子表数据的更新。这样的操做在有些ORM操做中已经实现了,但当本身code代码来实现的时候,特别是在屡次code的时候,感受老是那么烦心。

吐槽了这么多,是否有更好的解决方案呢?固然,在SQL里,咱们能够XML数据类型来消除主从表的设计。如图:

h566ugfb.png

上面的表结构设计,是否是有一个小清新的感受呢?很明显,能够把第一种表的设计缺陷给消除了。一个会议的相关信息都存储在了一个表的一条记录中,这样的数据看起来是否是更直观呢?

  a:获取一个预订会议的详细信息,我不须要进行多个表的链接查询,我要作的是只需用C#的Linq.Xml来解析查询出来的XML字符串便可。

  b:修改操做时,我只须要从新组合XML数据,一个Update就更新了与会议相关的信息,操做是否是简单多了。

表面上看这种设计已经完美了,可是用户的需求是无止境的,有一天,你收到了一个需求,查询某个用户参与过的全部会议(就是只要主持人,参与人,或者记录者中包括了这个用户,就把这些记录都给查询出来),Oh!My God  这种表结构设计应该怎么解决这个问题呢?其实能够用XQuery解决这个问题,还没接触过XQuery的那得赶快充一下电了。XQuery中最经常使用的有exist(),value()这些函数,这儿就不详细的介绍了,网上搜索一下有不少相关资料,若是有必要,我会把之前项目中用的XQuery技巧与

相关文章
相关标签/搜索