【数据库】_由2000W多条开房数据引发的思考、实践----给在校生的一个真实【练耙场】,同学们,来开始一次伟大的尝试吧。_.NET_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > .NET > 【数据库】_由2000W多条开房数据引发的思考、实践----给在校生的一个真实【练耙场】,同学们,来开始一次伟大的尝试吧。

【数据库】_由2000W多条开房数据引发的思考、实践----给在校生的一个真实【练耙场】,同学们,来开始一次伟大的尝试吧。

 2013/10/26 2:44:45  CatcherX  博客园  我要评论(0)
  • 摘要:缘起---闲逛博客园前几天的时候,在某一QQ群看到一条消息“XXX酒店开房XXXBTXX迅雷BT下载”,当时是一目十行的心态浏览,目光掠过时,第一反应时我邪恶了~以为是XX种子(你懂的~),所以并不感兴趣,呵呵....直到又回到博客园逛时,看到一篇最多评论的文章:看看多线程的效率有多差劲!-张浩华-博客园http://www.cnblogs.com/zhhh/p/3385751.html于是点击进去了。这时,我才回想起来,当时是自己邪恶想多了.....
  • 标签:一个 数据库 数据

缘起---闲逛博客园

前几天的时候,在某一QQ群看到一条消息“XXX酒店开房XXXBTXX迅雷BT下载”,当时是一目十行的心态浏览,目光掠过时,第一反应时我邪恶了~以为是XX种子(你懂的~),所以并不感兴趣,呵呵.... 直到又回到博客园逛时,看到一篇最多评论的文章:

看看多线程的效率有多差劲! - 张浩华 - 博客园

http://www.cnblogs.com/zhhh/p/3385751.html

于是点击进去了。这时,我才回想起来,当时是自己邪恶想多了...... 原来是2000w条开房数据记录的数据库,浏览了文章后,我表示对这2000w感兴趣了!于是,就催生了此文。

结缘---搜索引擎来牵线

看了上面提到的那文章,我决定也要玩一玩,不过那园友有点儿“懒”了,没有提供数据库以及Demo下载。好吧,这时候我们要发挥搜索本领了,几经搜索,最后是Google帮上的忙(百度搜索到的链接很多都已经被和谐了~)。 (温馨提示:近来上级严查水表,各位传播东西需小心~)。

一个小时过去了,1.7GB的压缩文件终于下载完成:

class="brush:csharp;gutter:true;">C:\[fuliba.net]某酒店2000W数据(解压密码:sjisauisa是就数据8很舒适好sjjss).rar
文件大小:1834815332字节
创建日期:2013年10月24日 15:38:55
哈希值(MD5):091AAC2B45D76CE1CD4248E7FFF1C00E

 解压后,约8GB多。

小巫见大巫

面对这千万条数据级别的数据库文件,先来看一看我的本机配置信息:

 1 操作系统名称    Microsoft Windows 7 Ultimate
 2 操作系统核心(Kernel)类型    Multiprocessor Free (32-bit)
 3 
 4 Microsoft SQL Server 2008R2
 5 Microsoft SQL Server Management Studio                        10.50.1600.1
 6 Microsoft Analysis Services Client Tools                        10.50.1600.1
 7 Microsoft Data Access Components (MDAC)                        6.1.7601.17514
 8 Microsoft MSXML                        3.0 5.0 6.0 
 9 Microsoft Internet Explorer                        9.10.9200.16686
10 Microsoft .NET Framework                        2.0.50727.5472
11 Operating System                        6.1.7601
12 
13 硬件概要
14  
15 CPU:        英特尔 Core i3-380M (双核)
16 主板:        方正 R410CP (英特尔 HM55 (IbexPeak-M DH))
17 内存:        6 GBytes
18 显卡:        ATI/AMD Mobility Radeon HD 5450/5470 (PARK PRO/XT GL)
19 硬盘:        东芝 MK3265GSX
20 
21 
22 处理器信息
23  
24 处理器:        Intel(R) Core(TM) i3 CPU       M 380  @ 2.53GHz
25 运行速度:        2533.3 MHz
26 核心/线程:        双核, 四线程
27 核心代号:        Arrandale SV
28 功耗:        25.0 W
29 插座:        Socket G1 (rPGA988A)
30 一级缓存:        指令: 2 x 32 KB, 数据: 2 x 32 KBytes
31 二级缓存:        集成: 2 x 256 KB
32 三级缓存:        3 MB
33 特性:        MMX SSE SSE-2 SSE-3 SSSE-3 SSE4.1 SSE4.2 EMT64 VT EIST TM1 TM2
34 
35 主板信息
36  
37 主板厂商:        方正
38 主板型号:        方正 R410CP
39 芯片组:        英特尔 HM55 (IbexPeak-M DH)
40 主板插槽:        2xPCI Express x1, 6xPCI Express x2, 1xPCI Express x16
41 USB支持:        v2.0
42 PCI-E支持:        v2.0
43 BIOS版本:        V1.12
44 BIOS日期:        12/21/2010
45 
46 内存信息(总计:6 GBytes)
47  
48 内存条1:
49 内存大小:        2048 MB
50 内存类型:        DDR3 SDRAM
51 制造商:        三星
52 制造日期:        2010年第39周
53  
54 内存条2:
55 内存大小:        4096 MB
56 内存类型:        DDR3 SDRAM
57 制造商:        三星
58 制造日期:        2012年第1周
59 
60 显卡信息
61  
62 显卡芯片:        ATI/AMD Mobility Radeon HD 5450/5470 (PARK PRO/XT GL)
63 显存大小:        512 MB of DDR3 SDRAM
64 显卡型号:        ATI/AMD Mobility Radeon HD 5450/5470 (PARK PRO/XT GL) [宏碁]
65 显卡BIOS版本:        012.020.000.050.038152
66 频率:        157.0 MHz
67 
68 
69 存储信息
70  
71 存储器1:
72 控制器:        Serial ATA 3Gb/s
73 型号:        东芝 MK3265GSX
74 容量:        305,245 MB (320 GB)
75 转速:        5400 RPM
76 缓存:        8192 KB
77 NCQ功能:        支持, Max. Depth: 32
78 S.M.A.R.T.:        存在, 开启
79 48bit LBA:        支持, 开启
80 工作时间:        7088小时 
测试机配置信息

 

应该还算可以吧?有点别扭的是在32位系统上硬是要它使用(破解--映射方式)6GBytes的内存,呵呵,会不会有什么后患呢?

 


 

之前学习使用的数据库文件多为MDF格式的,直接附加就能使用,但现在这个解压后是.bak格式的,是备份出来的,所以不能以附加的方式进行附加,

而是用【还原】的方式,如图:

也可以尝试用命令的方式还原bak文件并建立到一个新的数据库,(仅供参考,没实践过)

/*
备份数据DB 到.bak文件。然后利用此bak文件恢复一个新的数据库DBTest。
*/
USE master
BACKUP DATABASE DB 
  TO DISK = 'g:\DBBack0930.bak' 
RESTORE FILELISTONLY 
  FROM DISK = 'g:\DBBack0930.bak' 
RESTORE DATABASE DBTest 
  FROM DISK = 'g:\DBBack0930.bak' 
  WITH MOVE 'DBTest' TO 'E:\Program Files\Microsoft SQL Server2005\Data\DBTest.mdf', 
  MOVE 'DBTest_log' TO 'E:\Program Files\Microsoft SQL Server2005\Data\DBTest_log.ldf'
GO 

 

 

OK!我们就开始还原吧,点击确定之后,我呆住了,机器也似乎呆住了,那还原的状态进度一直(2分钟内)是0,

鼠标光标变成了圆圈忙碌状态,系统瞬间变得很卡,(汗~~在校生,没见过什么大场面,被这还原进度惊呆了,各位不要见笑哦!),

又过了一分钟,终于有反应了,状态的百分比显示20%+,以步进6%左右递增,不会处于“卡死”状态了,

又过了几分钟,终于完成了。以前,课堂练习的附加,还原文件几乎都在秒级完成,几乎没有什么时间等待的概念,

这次可谓见识了什么叫海量(不过,但各位老鸟中,2000w,可能还只是沧海一粟(sù))数据。

 


还原成功!于是心急着马上查一查心中的她,是否榜上有名了。不加思索,就来了一条SQL语句:

select * from dbo.cdsgus where Name='女神'

 噢,又一次惊呆了!在此先省略......字, 

慢,别想多了,不是找到了女神的名单,而是电脑再次进入了呆住了的状态,只是查询还在在执行中,一开始,我还以为是内存太小,

CPU太差了,Ctrl+Alt+Del呼唤了任务管理器出来:

 

上图告诉我,不是CPU,内存的错,也就在这时,一个闪闪的红星引起了我的注意~~

对,你猜对了!就是硬盘的读写状态提示灯,它在飞快的闪烁,平时,它只会偶尔闪闪。于是,我再次从任务管理中调出【资源监视器】来观察情况,

 

“卡住”的原因找到了,跃然上图,不多说了。以前,很少会关注硬盘IO问题,毕竟经常性地Copy大文件的机会不多。而这次,我才真正关注起硬盘IO问题,在这给自己和各位对IO陌生的朋友补充一下:

读写IO(Read/Write IO)操作

磁盘是用来给我们存取数据用的,因此当说到IO操作的时候,就会存在两种相对应的操作,存数据时候对应的是写IO操作,取数据的时候对应的是是读IO操作。

单个IO操作 当控制磁盘的控制器接到操作系统的读IO操作指令的时候,控制器就会给磁盘发出一个读数据的指令,并同时将要读取的数据块的地址传递给磁盘,

然后磁盘会将读取到的数据传给控制器,并由控制器返回给操作系统,完成一个写IO的操作;

同样的,一个写IO的操作也类似, 控制器接到写的IO操作的指令和要写入的数据,并将其传递给磁盘,磁盘在数据写入完成之后将操作结果传递回控制器,

再由控制器返回给操作系统,完成一个写IO的操作。单个IO操作指的就是完成一个写IO或者是读IO的操作。

 

 对于经常做网络,服务器的来说,I/O不好反映到网站上就是网站页面加载慢、卡、读取数据库慢,

甚至导致网页打开超时显现。

 

关于IO瓶颈处理的推荐文章:
Understanding Disk I/O - when should you be worried?
http://blog.scoutapp.com/articles/2011/02/10/understanding-disk-i-o-when-should-you-be-worried

贝塔中的DBA » IO系统性能之一:衡量性能的几个指标
http://www.dbabeta.com/2009/io-performence-01_several-concepts.html

等待了200多s,终于有结果了:

呵呵,终究没有出现女神的名字。

面对这2000w,一条select * from XXX就把我汗颜了,我在想着下一个要查谁的时候,内心一个念头把我拉住了。

不能这样折腾硬盘,伤不起.....


 

 

给在校生的练耙场---可以实践检验平时学习的理论知识

【背景】

平时课堂练习的项目,数量都是几十条为主,也不想无聊去自己建立上万条非真实数据去测试。

【实战】

查询一条数据就要等待200多s,你有这样的时间浪费吗?也就在这时,平时学习的理论知识要派上用场了-----【索引】

【四两拨千斤---索引来支招】

上面提到提到了,执行语句:  select * from dbo.cdsgus where Name='女神'  花了200多秒,

假如结果只有一条,各位猜一猜执行:

select top 1 * from dbo.cdsgus where Name='女神'  要花多长时间呢?  --留给各位实践一下。

好吧,为了快速地找到那个她,我们为字段名Name建立索引:

Create Index Index_ByName on dbo.cdsgus(Name)  --由于记录多,建立索引的时间很慢,耗时:03:49

这时,再去查询执行同样的查询,大家猜一下这一次所花的时间,与刚才的耗时对比,又一次让我惊呆了。

平时课堂练习的项目几乎体会不到索引对于检索速度的影响,这次可谓实践,领会了!

上面注释提到建立索引就花了209秒,那它在背后究竟做了什么呢?建立索引后再次查询,为什么会让我再次惊呆呢?

 

天下没有免费的午餐,索引能为我们的检索速度起到了四两拨千斤作用,那么,肯定也是要付出代价的。你知道有何代价么?

在课堂中,关于索引的缺点只有理论的提到几句:

第一,创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。 
第二,索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大。 
第三,当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。 

很少试实践证明,即使实践了,由于是几十,百条数据的项目,感受不到。

这次可谓实践了。

针对以上缺点,

第一条,209s 耗费时间这个深有体会了。

第二条,需要占用物理空间,请看以下数据对比:

未为字段Birthday建立索引前的文件大小:
2013/10/25  00:52     9,379,119,104 shifenzheng.mdf
2013/10/25  00:52        40,239,104 shifenzheng_1.LDF

建立索引后的文件大小:
2013/10/25  10:49     9,994,633,216 shifenzheng.mdf
2013/10/25  00:52        40,239,104 shifenzheng_1.LDF

对于第三条,这里就不实践了,毕竟这个数据库是用来查数据的用的,从第一,二条缺点也可心推断出第三条了。

对于经常用来查询的字段,建立索引的利大于弊,复习一下:

第一,通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。 
第二,可以大大加快数据的检索速度,这也是创建索引的最主要的原因。 
第三,可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。 
第四,在使用分组和排序 子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。 
第五,通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。

 

 

有了索引后,我们查询就方便多了,大家想不想知道我们的DuDu是否入围呢? 大伙来围观:

select * from dbo.cdsgus where Name='杜勇'   
--耗时 4s
--(393 row(s) affected)

篇幅有限,也防和谐,就不在这公布具体数据,嘻嘻!大家想一想,同名的人在国内还是挺多的嘛!

 

由于我们在这里都是直接对数据库查询,也就不提供应用层的界面了,如Winform,WebFromt等,如果做那些,

要考虑到储存过程,高效分页查询等,所以下文继续只是用SQL语句演示。


 

 

疱丁解牛---分析表结构设计

上面从实用主义出发,走的是:下载---》还原---》查询结果,这样的路线,根本没有从底层,结构上的东西去想一想。

嗯,那现们静下心来,看一看这个表设计如何,

Column_name  Type Computed  Length    Prec    Scale   Nullable TrimTrailingBlanks    FixedLenNullInSource    Collation
Name      nvarchar    no    4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
CardNo    nvarchar    no    4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
Descriot  nvarchar    no    4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
CtfTp    nvarchar    no     4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
CtfId    nvarchar    no     4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
Gender    nvarchar    no    4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
Birthday    nvarchar    no  4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
Address    nvarchar    no   4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
Zip    nvarchar    no    4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
Dirty    nvarchar    no    4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
District1    nvarchar    no    4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
District2    nvarchar    no    4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
District3    nvarchar    no    4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
District4    nvarchar    no    4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
District5    nvarchar    no    4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
District6    nvarchar    no    4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
FirstNm    nvarchar    no    4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
LastNm    nvarchar    no    4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
Duty    nvarchar    no    4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
Mobile    nvarchar    no    4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
Tel    nvarchar    no    4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
Fax    nvarchar    no    4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
EMail    nvarchar    no    4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
Nation    nvarchar    no    4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
Taste    nvarchar    no    4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
Education    nvarchar    no    4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
Company    nvarchar    no    4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
CTel    nvarchar    no    4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
CAddress    nvarchar    no    4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
CZip    nvarchar    no    4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
Family    nvarchar    no    4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
Version    nvarchar    no    4000                      yes    (n/a)    (n/a)    Chinese_PRC_CI_AS
id    int    no    4    10    0    no    (n/a)    (n/a)    NULL
View Code

 

可以看得出作者很懒,除了主键id,其它字段一律用 nvarchar,长度4000应付,其实看到这里的时候,我有点怀疑这些数据的真实性(是否随意生成)的。

nvarchar(n)    变长    处理unicode数据类型(所有的字符使用两个字节表示)    
n 的值必须介于
14,000 之间。字节的存储大小是所输入字符个数的两倍。所输入的数据字符长度可以为零

 

验证数据真实性(希望更多朋友提供准确的方式)

带着疑问出发,我用了这个语句来查询:

select  * from dbo.cdsgus where Address like 'XX省XXx市XX镇XX村%'   --X代表地点名称

呵呵,还真找到了几个熟悉的小伙伴,尚且当它是真的吧。又或者原数据库被人加工、整理过之后,随便建立了一个表保存起来的之后再备份出来放在网上的。

(我就纳闷了,整个备份文件还原之后仅只有一个表~)

说回正题,我们再看看:

Name    Owner     Type          Created_datetime
cdsgus  dbo       user table      

作者是夜猫子,看一看创建日期:2013-05-23 04:02:21.120

ID自动增涨列:

Identity    Seed    Increment    Not For Replication
id             1        1            0
index_name        index_description                  index_keys
Index_Birthday    nonclustered located on PRIMARY     Birthday
Index_ByAddress    nonclustered located on PRIMARY    Address
Index_ByName    nonclustered located on PRIMARY       Name
PK_cdsgus    clustered, unique, primary key located on PRIMARY    id

原本只有id默认主键索引,Name,Address,Birthday是我后来加上的。

constraint_type        constraint_name    delete_action    update_action    status_enabled    
PRIMARY KEY (clustered)    PK_cdsgus    (n/a)    (n/a)    (n/a)    (n/a)    id

ok!表字段结构我们看完了,尽管这这个数据库只有一个表,表中只设置了一个id主键。但从结果显示中,

我们可以看出,其实有几个字段是作外键使用的,

如下图中的:District1--6,family,id等。

既然了了外键,那么应该还有其它的数据表,希望哪位可以提供上来,呵呵。


 

 

天马行空---数据挖掘、分析、利用

数据有了,除了用来练习几个select 语句还能有什么用呢?

这个时候,该发挥我们的天马行空思想了,看一看,想一想里面都有什么了?

由于里面的数据有其真实性,且有了身份证号码,邮箱地址,手机号码......嘿嘿,想到了吧?不要用来做坏事哦!

  • 骗子们得到数据后,可能会用来群发敲诈短信;
  • 广告诉们可能会用来传广告;
  • 数据挖掘专家可能会用来了解各地入口入住人数,年龄阶段,分布时间范围等。
  • ......

我们也来学着分析一下,(在园子里的应该都接触过sql语句,下面直接取样分析)

地区分布:(以北,上,广为例)

select  count(*) as '北京' from dbo.cdsgus where Address like '北京%'
select  count(*) as '上海' from dbo.cdsgus where Address like '上海%'
select  count(*) as '广东' from dbo.cdsgus where Address like '广东%'

结论:留给大家思考......


 

年龄分布:

select  count(*) as '00后' from dbo.cdsgus where Birthday like '20%'
select  count(*) as '1990后' from dbo.cdsgus where Birthday like '199%'
select  count(*) as '1980后' from dbo.cdsgus where Birthday like '198%'
select  count(*) as '1970后' from dbo.cdsgus where Birthday like '197%'
select  count(*) as '1960后' from dbo.cdsgus where Birthday like '196%'
select  count(*) as '1950后' from dbo.cdsgus where Birthday like '195%'
select  count(*) as '1940后' from dbo.cdsgus where Birthday like '194%'
select  count(*) as '1930后' from dbo.cdsgus where Birthday like '193%'
select  count(*) as '1920后' from dbo.cdsgus where Birthday like '192%'
select  count(*) as '1910后' from dbo.cdsgus where Birthday like '191%'
select  count(*) as '1900后' from dbo.cdsgus where Birthday like '190%'
select  count(*) as '1800后' from dbo.cdsgus where Birthday like '180%'

结果:80后作为主力军,你是否在其中呢?

类似的模糊查询,大家可以灵活变通,如查询客户是移动的用户还是联通的多(根据手机号码前N位),邮箱后缀名等。


 

建议

查询示例到此告一段落,现在网上也有不少人把这数据库作为数据源,可以通过Web页面进行查询了,

但我用了几个都很不理想,速度慢得可怜,有时候真怀疑他有没有建立相应的索引了,最大的局限性是:仅能通过身份证,姓名去查。

对于作为程序员的你,你接受这样的低权限吗?

所以,建议大家有空还是应该找到这文件,在本地测试,推荐给所有在校生,可以用来练习一下多数据查询,优化问题。

当然,如果哪位朋友有资源的话,建立一个Web页面,可以直接输入sql命令来查询的那就更好了。

 


 

最后来一张关于数据价值转化的图:

我们现在得到数据库了,直接到达了加工车间这一层,至于怎样去发掘,那就要看你们的创意了。

 


 

总结

自从在学校交了210元的费用考了个所谓的的数据库工程师资格证(学校要求必须要考,但没什么技术含量),

之后比较少接触SqlServer数据库了,转眼,10月底了,再过一段时间就要准备实习了,目前还是在校生。

这次藉由这个2000w来温习了一下相关的基础知识,

磁盘IO性能问题,数据备份,恢复,索引,模糊查询,函数调用,大数据分析,挖掘,利用等。

 

抛砖引玉---期待亮点评论

此文,仅仅代表一个在校生初试2000w条记录的数据库的浅显实践,泛泛而谈,个中的结论,推断难免轻浮、果断。

不足之处,还望各位资深读者多多指导,斧正本文的错误论点。

 


如果本文吸引了你,为你带来了灵感,帮助,麻烦你轻轻点击【推荐】,

你的热心评论,推荐,是我分享文章的强大动力。谢谢阅读!

 

 

发表评论
用户名: 匿名