之前的版本里面SQL Server已经可以支持Filestream的功能,通过Win32 API或TSQL来访问存储在文件系统中的BLOB数据,但是最大的问题来自于与遗留应用程序的兼容性无法解决,如果相提高性能必须通过TSQL先获取文件的handle然后用API访问文件,很多程序使用了Copy等Windows命令或类似于.net framework File类的方式来处理,这样一来好的功能也无法广泛的使用。在SQL Server 2012中提供了一个FileTable的功能,通过文件驱动的方式模拟了一个共享目录,用户的应用程序可以通过文件API直接对有SQL Server管理的Blob进行操作,这样一来与遗留程序的兼容性就可以解决了。但是目前的产品里面也不是非常的完美,主要就是FileTable的列是固定的,无法根据用户的需求进行自定义,同事对于文件夹的深度也有限制,这些小问题在一些特殊的情况下还需要进行一些定制的操作,但是有了通过文件系统的访问方式已经很不错了,至少简单的通过数据库对文件系统进行管理的基本功能已经有了,剩下的额外功能倒是可以有ISV定制开发了。
svs
昨天帮同事优化了一个小程序,程序的功能很简单,将每天产生的若干压缩包解压读取清单文件入库,并根据清单文件的情况选择包内的文件对数据库进行字段更新,每条记录被更新的2个字段分别存储在2个文件中,文件都是小文件,90%以上小于2K.压缩文件有1600左右,解压之后文件数量在82W个。
一般处理的思路就是将文件解压,然后读取清单,与数据库比较去重,入库,更新,删除文件,这些功能都可以在多线程下完成。逻辑思路就是这样,但是对于性能的影响主要在程序设计中对于文件的处理上。82W个文件多线程解压至少要25min,问什么这么慢呢?其主要原因并不是在CPU上,IO设计上是关键。
计算机的存储主要是用来持久数据的,根据持久的时间、访问的模式来看,主要就是HDD、RAM、CPU Cache.我们的这个应用文件IO主要是拼IOPS。我没有SSD,所以这个指标也不太高,那就只能考虑RAM了。如果处理文件的尺寸比较大,除了HDD我们肯定是没有办法,但是如果文件的尺寸很小内存就是一个很不错的选择。由于我的业务只需要读取到压缩文件的内容,对于文件是否解压实不关心的(解开最后也会删除),最佳方式是在内存里面进行解压操作,内存的IOPS比HDD高出若干数量级,只要控制好线程和内存的使用就可以了。处理压缩文件可以先读取文件中的文件列表,找出需要的文件进行解压,这样也能减少IO次数。
.net 4.0里面的并行类可以很方便的给我们提供多线程操作的功能,用起来也很方便。
最近在几个公司内部的项目中使用了EF的Code First开发模式,感觉不错,但是也遇到了一些小小的问题.首先对于EF来说与数据库之间有多种开发模式,可以先设计类或者先设计数据库.从程序设计的角度来说Code First是一种很不错的方式,节省了我们对于数据库设计的工作,极大地提高了系统开发的效率。但是如果业务的需求发生变化,Code First就会遇到一些麻烦。
我们之前开发的系统上线2个月之后对于实体做了一些小修改,部署到服务器之后有一些View就出现了500的错误,其原因就是EF Code First在创建数据库的时候针对实体类作了Hash,并将Hash存储在数据库中的EdmMetadat表的ModelHash字段。当系统运行时,EF Code First会将运行的实体与数据库中的ModelHash进行比较,如果不同就会认为系统出现了变化,抛出异常。当然EF提供了一些数据库初始化的功能,但是当检测到变化后,初始化策略只能将原有的数据库删除重新根据实体关系建立数据库。如果数据库中已经有一部分数据,这些数据将会丢失。
目前我找到的一个解决方案是手工处理ModelHash的更新。如果实体发生变化,手工生成数据库变更的脚本,然后再测试机上运行系统,并从新生成的测试数据库中获取ModelHash的值,将这个值更新到生产库上就可以了。当然你也可以写的自动化一些,将测试库里面的ModelHash自动更新到生产库上。
在SQL Server 2008 R2 上有一个叫Data-Tier Application的组件,可以用来帮助用户快速开发和部署数据库应用程序。在部署和升级数据库的时候可以将原有的数据库保存并重新命名,而更新的数据库中还可以保留数据。如果可以将EF Code First与Data-Tier Application结合到一起,应用开发的效率会更高,但是目前还没有听说微软有这方面的打算。
Filetable是一个很有意思的一个功能。很久很久以前微软曾经想把Windows的文件系统放到SQL里面来管,这样就能将结构化和非结构化的数据整合在一个平台来管理,而且可以嵌入在Windows的内部来实现。在Windows Vista年代曾经有一个叫WinFS的原型,当然最后这个东西还是没有最终Release。在SQL Server 2008里面微软还是希望将数据的应用(包括非结构化数据)整合到数据库里面,毕竟之前已经做了Text和Image数据类型,而且在SQL 2005里面也有了Max的数据类型,基本上可以说快要准备好了,所以在SQL 2008里面提供了一个新的数据类型叫Filestream,这个数据类型就不多说了,没听过的就去Bing一下吧。我在这个SQL 2008里面也针对Filestream做了一个项目,利用了RBS的框架写了一套具有负载均衡的RBS Provider,可以通过RBS为客户提供统一的数据访问接口,后面接上我的Provider就可以在SQL中管理Blob数据,当然数据是海量的,设计容量就要20TB。但是当时也觉得会有一些问题,其中最主要的还是在接口上。Filestream提供了Win32和TSQL这2中接口,但是对于应用程序来说必须针对Win32接口做特殊的处理,因为Win32接口处理文件的时候必须要先提供一个句柄,而这个句柄必须通过Filestream的特殊函数才可以获取,总之对于应用程序来说不是很友好。虽然可以通过RBS来进行扩展和包装,但是对于遗留应用来说除了重新写接口代码别无选择。
在Denali中(CTP2)里面,我终于看到了这个FileTable。FileTable是一种特殊的表,这个表有固定的列和索引,这个表的结构是不能修改的。其中存储了文件的基本信息和内容,当然内容列肯定是Filestream。和之前最大的变化是Denali在驱动层做了一些修改,将FileTable转换成一个通用的UNC路径,也就是说我们可以通过Windows Explorer来直接访问数据库里的这个表。这样一来对于现有的遗留应用程序来说就好多了,可以在不改变应用的前提下直接使用Filestream的特性,就像访问远程的共享目录一样,而文件的管理和备份直接在SQL里面完成,与应用程序数据也能完美的结合。
在FileTable上最适合的应用就是扩展的一些文件搜索应用了,例如Lucene。如果你觉得SQL的FTS不够强大(确实差一些,尤其是中文),就可以通过Lucene直接去读取FileTable,而且不需要在写特殊的代码,只需要配上分词就可以了。在SharePoint 2010里面已经提供了一个Filestream的RBS Provider,通过这个Provider可以将SharePoint的Blob数据写到数据库里面去(存储在文件系统上),只不过原始的Filestream对于应用来说是一个噩梦,用FileTable吧,改改配置文件就够了。
另外还要说一下,FileTable毕竟还是数据库,不是NTFS文件系统(你可以把它看成一个FAT32),一些NTFS支持的加密及压缩属性还是不支持的,至少是在文件系统的驱动上不支持。还有就是负载均衡,目前还有相应的解决方案,当然这个是可以进行二次开发的,如果我把之前的那个Provider改改就行了,且也非常简单。
分页已经是很久远的话题了,很多时候都是靠着一些技巧来实现分页的,随着SQL Server版本的不断更新我们有了更多的选择,之前有人总结了一下我们现在可以使用的一些分页技术 http://www.cnblogs.com/qiuwuyu/archive/2011/03/21/1989870.html。在SQL 05/08里面我们可以使用CTE&Row_Number的方式实现分页,在SQL 2000里面我们基本上都是使用Top和Set RowCount的方式实现。你会发现高版本上提供的语句更加简洁和可读,降低了逻辑的复杂性。在下一个版本中Denali中,SQL Server在Order By函数中提供了一组语句可以实现分页并且从性能到程序的可读性有很大提高。
下面是程序的代码
USE AdventureWorks2008R2;
GO
CREATE TABLE dbo.AppSettings (AppSettingID int NOT NULL, PageSize int NOT NULL);
GO
INSERT INTO dbo.AppSettings VALUES(1, 10);
GO
DECLARE @StartingRowNumber tinyint = 1;
SELECT DepartmentID, Name, GroupName
FROM HumanResources.Department
ORDER BY DepartmentID ASC
OFFSET @StartingRowNumber ROWS
FETCH NEXT (SELECT PageSize FROM dbo.AppSettings WHERE AppSettingID = 1) ROWS ONLY;
怎么样不错吧,而且可以结合上Snapshot,确保返回结果的稳定
USE AdventureWorks2008R2;
GO
– Ensure the database can support the snapshot isolation level set for the query.
IF (SELECT snapshot_isolation_state FROM sys.databases WHERE name = N’AdventureWorks2008R2′) = 0
ALTER DATABASE AdventureWorks2008R2 SET ALLOW_SNAPSHOT_ISOLATION ON;
GO
– Set the transaction isolation level to SNAPSHOT for this query.
SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
GO
– Beging the transaction
BEGIN TRANSACTION;
GO
– Declare and set the variables for the OFFSET and FETCH values.
DECLARE @StartingRowNumber int = 1
, @RowCountPerPage int = 3;
– Create the condition to stop the transaction after all rows have been returned.
WHILE (SELECT COUNT(*) FROM HumanResources.Department) >= @StartingRowNumber
BEGIN
– Run the query until the stop condition is met.
SELECT DepartmentID, Name, GroupName
FROM HumanResources.Department
ORDER BY DepartmentID ASC
OFFSET @StartingRowNumber – 1 ROWS
FETCH NEXT @RowCountPerPage ROWS ONLY;
– Increment @StartingRowNumber value.
SET @StartingRowNumber = @StartingRowNumber + @RowCountPerPage;
CONTINUE
END;
GO
COMMIT TRANSACTION;
GO
Offset N Rows Fetch Next N Rows Only 这种可读性已经是最好了,简单到不能再简单了,如果我的程序员还不会用,那只能Fire他了。
在Warm cache的情况下(没有物理读,只有逻辑读),新的语句对于CPU的使用比较低,大家可以测试一下。
这个功能目前在CTP1中都可以实现了,大家可以从http://www.microsoft.com/downloads/en/details.aspx?FamilyID=6a04f16f-f6be-4f92-9c92-f7e5677d91f9 进行下载。
目前由于还没有发布,所以在EF中也无法得到支持,个人感觉应该在后续的EF中提供这种支持,这样对于程序员来说就一点SQL都不用写了,否则还要自己写一个extension
自从SQL 2000以后在SQL Server上SSIS就成了一个非常重要的产品。相比DTS,最大的变化不是在那些转换的控件上,而是运行体系,清晰的运行方式让开发人员可以更加深入的理解任务和数据的关系,能够将整个数据集成的项目清晰的分割成不同的阶段和任务。新架构下产生了Data Flow和Control Flow的概念。这次就重点聊聊Data Flow,希望读者们能慢慢理解其中之精髓,不明白的可以留言。(通常情况下我太愿意贴图,因为之前就没学会怎么搞图片)
Data Flow中文就是数据流,实际上Data Flow数据Control Flow中的一个任务。一个SSIS包中可以没有Data Flow但是不能没有Control Flow,例如SQL Server中的维护任务就可以是一个SSIS的包,用来备份数据或者维护索引,这种包就没有Data Flow。Data Flow主要适用于处理数据,在Data Flow中,数据从源读取写入目标,中间可以根据数据要求进行转换(结构,内容或类型)。数据从源到目的过程中,完全都是在内存中进行转换,也就是说一旦数据进到了Data Flow,在硬件上就只与内存、CPU缓存及CPU打交道了。Data Flow是依照Pipeline模式进行设计的,也就是说数据操作可以理解为逐行处理。当然数据读取和写入还是和这些数据源或目标有关系,可能也会有批的操作,但是转换上只能在内存里面逐条进行(部分操作除外,后面会提到)。如果是Pipeline模式,硬件上就需要有更快的CPU及内存的频率,这些对于性能来说很重要。但是如果不做特殊的设计和处理,系统很容易达到一个瓶颈,因为每一个pipeline只能够理由一个线程来操作,无论你的服务器有多少个核,只能发挥1个核的作用。当你发现其他的子系统压力也不大,但是SSIS转换的速率却不高的时候,基本上都是这种问题所致。
另外在由于数据通过pipeline中进行流动,如果有一个转换将所有的数据堵在内存里将极大的影响SSIS运行的效率,而且如果数据量非常大的时候可能会把内存耗尽,就像北京堵车一样,没有事故还可以,有了事故就全线飘红。SSIS可没有TempDB,物理内存没了就是没了。这种情况基本上都是在聚合组件和排序组件上,所以要尽量避免使用他们,除非万不得已,否则小心使用。
这个问题我觉得对于一般的开发人员来说不是很好解决,如果你对数据库及SSIS没有很深理解的话,基本上很难,而且这个问题是无法通过升级硬件来有效解决的(目前CPU的发展并不是高主频,而是更多核)。这个问题只能通过设计来解决,但是这可是一门学问,涉及的领域就是并行处理。并行处理需要考虑很多问题,包括数据源和数据目标的设计,控制流设计等。通过这些巧妙的设计,让我们的包能够通过更多的线程来运行更多的pipeline,当然这个更多2字并不是代表无穷多,因为当线程数量达到一定规模的时候,整个系统的瓶颈可能就会出现在其他的子系统上了,多数情况可能在网络IO或者磁盘IO上。
设计并行的SSIS包比较复杂,这里我给大家介绍一下RRD(Round-Robin Distributor)。这个组件目前还没有发布,但是可以讲讲这个组件的实现方式。实际上这个组件就是将输入pipeline根据你的data flow下层引出的执行线程数量动态的分发数据,这个功能类似于多播,只不过多播里面分发的数据是相同的,对同一条数据复制了多份并产生多个执行的线程,RRD上分发的数据是不同的。这样如果结合上适当的数据源就可以在data flow中实现并行。如果哪位在项目中需要使用可以联系我。
最近在和SSIS产品组交流的时候,我也提了一些建议,主要都是和性能相关,他们也应该与时俱进一下,让用户能够更好的利用一下多核。
在TechEd 2010上讲了一门如何构建企业级ETL的Session,可能是因为技术方面的东西太多,没有什么太炫的Slides和Demo,听众反映一般,8.08分不太高,这里在把东西解释解释。
当时主要是因为工作比较忙,准备PPT和Demo就用了1天半的时间,确实有点仓促了,但是内容上感觉还是比较丰满的,主要目的就是给听众一个理念上的引导。
目前在企业里面用SSIS的客户还是比较多,但是大多数人还仅仅停留在如何使用SSIS进行转换,很多学习的教程也都是写那些控件的使用方法。实际上工程项目中遇到的一些实际问题是不能通过简单的控件来解决的,必须要有巧妙的设计,这个道理就像写程序一样,否则也就不会有设计模式这个领域了。
SSIS中提供了一个扩展性很强的框架,Control Flow&Data Flow,具体概念我就不多说了,有人反映我讲课的时候经常重复这些东西,其实也不是重复,只是很多人没有深入的理解。我们的设计其实很多地方都会在Control Flow里面进行体现,所以要有好的设计,就必须先理解Control Flow。除了理解Control Flow外,对于Parameter和Configuration的灵活应用也非常重要,这些都是在进行控制的过程中必不可少的连接技术,没有这些东西也无法把不同功能的包和流程组织在一起。另外一个重要的功能就是Script,Script是整个包设计里面的灵魂,很多动态功能都要依赖于此,而且Script中写的不再是vbScript和VB.net,我们可以写C#了,功能上丰富多了,尤其是对象参数和C#的结合。我们可以设置任何Object对象参数,在Script里面就意味着我们可以传递更丰富的内容,而不仅仅局限在基本数据类型,例如int,string等,我们可以传递类似于array,list等更高级的参数类型,提供更灵活的调用。有了Parameter,Configuration,Script,我们可以借助于一些容器控件来实现更多功能,具体能实现什么,就看你想怎么设计了,至少SSIS已经提供了这个框架。
另外对于企业来说SSIS的性能也是需要特殊注意,因为SSIS操作过程中对于系统整体来说都会有短时的压力,需要在规定的时间窗口内完成ETL的过程,否则可能会影响其他业务系统的正常运行。大部分用户都会遇到性能问题,而多数性能问题都是由于下列原因引起的
- 数据源读取速度
- 目标写入速度
- 转换过程设计
数据读取速度
这个部分的原因要看数据源系统的情况。我们都希望对整个系统来说有一个有效的方式进行性能评估及性能优化,所以我建议这个数据源部分使用可以分割边界的系统,也就是说不要用可能过分依赖于网络,远程站点等异步的数据源系统。文件和本地局域网数据库都是比较好的选择,至少网络延时可以忽略不计,否则的话性能上的SLA很难评估,相比局域网数据库或文件系统性能的稳定性比远程HTTP或Web Service要好很多。有了稳定的数据源就要评估这种数据源的极限读取能力,也就是做Baseline,这个很重要,因为你的系统性能的极限和这个有很大关系,但是这个极限并不是不能突破,关键看设计,至少在没有特殊设计的情况下,极限性能就是对于数据源单纯的读取性能。如果数据源是关系型数据库,就需要对数据库或者查询进行优化。
目标写入速度
这方面我就不多说了,微软专门有相应的文章写了如何进行快速的数据装载,主要的问题就是No Log或者Mini Log的设计。这个过程也相对好进行评估。用BCP就能测试出来。
转换过程设计
这个部分相对来说可以做的事情比较多。SSIS的Data Flow就是Pipeline模式,你要做的事情就是让数据能够流动起来,别有堵塞。聚合、排序都会有阻塞,都要慎用。另外Merge Join也要注意,这个需要2个流入的数据源是排序的,这种排序最好考虑在数据源里面实现。如果数据源不支持,例如文件系统,可以通过SQL做一个Staging的数据库,临时排序使用,至少可以利用内存和tempdb排序,而SSIS都是在内存里面排序,你不一定有足够大的内存,至少我遇到在224G内存的服务器上出现内存不足的情况,当时的数据量是1TB。另外就是内存的占用和我们每行数据的长度及数据类型都有关系,要精确设计一下,不能用Select *这种方式,如果文件系统,需要在读取的时候转换一个准确的数据类型。
上面说了3中在Data Flow常见的设计问题和思路,在Control Flow里面的事情比较多,但是最常见的就是并行设计。很多情况下并行设计能大幅度提升你系统的性能。多数情况下,SSIS服务器并没有发挥出系统的整体性能,只要找到不同时期的性能瓶颈,逐步优化后都能有很好的性能提升,但是并行是大家经常忽略的一种情况。如果你发现你的IO,网络,内存都不存在瓶颈的时候,你要提升性能,就要注意看一下CPU了。对于CPU利用率来说,我们不能看整体,因为多核和多CPU情况下,我们必须要看每一个核的利用情况,很有可能一个核已经100%利用率,但是系统只能一个线程,这个时候必须要考虑多线程设计。SSIS设计上并没有直接提供对于线程的控制,真的没有做到与时俱进,目前很多服务器上都是4-6个核,4CPU的服务器也很多,通常每个核提供20MB/s以上的吞吐量,你可以评估一下,你的系统能够做到的性能极限是多少。我在一个测试过程中在96核的系统上可以做到大约1TB/s的数据吞吐,这还是我限制了40个线程。但是线程的设计比较复杂,需要考虑数据源的形式及特征以及Control Flow中流程的关系。基本上都是通过脚本结合流程控制组件来动态控制,目前除了这个没有其他的办法。微软目前可以提供一个Data Flow层面的转换组件RRD(Round Robin Distributor)在Data Flow里面实现多线程,目前这个组件还没有Release。如果大家在项目里面有需求,可以找我联系。
先写到这里,后面有时间在讲讲如何使用Control Flow。
又折腾了1个月,新的版本release了,这次的UI改动比较大,接受了很多网友的意见。现在的实验都是系列了,以后可以搞一个从入门到精通的系列。而且后续还会添加微软云计算的内容。
前几天和开心抽烟的时候聊了一下HTML5,看似功能很强大,但是浏览器支持上还是有一些小问题,毕竟国内还有很多IE6(我们公司就有一堆)。另外HTML5能做的SL也都能做,让开发者不太好选择。有人说SL需要安装插件,但是Flash也需要,我们的那个平台也需要,所以我觉得插件根本不是问题,平台好才是真的好,管他有没有插件。我们的那个平台之所以没有使用SL,主要的原因还是SL太安全了,安全的有一些功能非常难实现(当然也不是绝对不能,但是相当困难),SL调用COM还是挺不靠谱的。HTML5我们更不敢用,至少现在不敢,虽然我们的平台需要客户端使用IE,但是至少还没有说需要IE9吧。
最近平台在做一个活动,找bug,提意见,领奖品,有兴趣的可以去http://www.tech-labs.net上面体验一下。
另外最近添加了SQL 2008 R2的实验。
经过半年多的努力第一个云项目及产品基本上快完成了,目前主要用在产品培训及教育领域。UI比之前的版本强了很多,而且速度也快了很多,ADSL的链路就会有很好的体验。现在开放了一个平台给技术爱好者使用,也算是公益事业了。如果有兴趣可以访问我们的这个智慧实验室,这个平台上目前提供了一些技术学习的资源,包含VS2010\ASP.NET MVC\F#等新技术。大家有兴趣可以上去看看。
好久没有写点东西了,不是没什么可以写的主要是工作很繁忙,事务太多了。之前1年的时间我们的团队做了一个半成品,但是由于市场及政策的限制,还没有到市场运作的阶段。虽然不是胎死腹中,也要在让他多在娘胎里面住上一段时间。
最近我们的一个团队在做一个私有云的项目,希望利用虚拟化技术将OS的功能发布出来。所有想法的源头来自于我们的一个客户,他们希望有一种基于互联网的IT体验,就是希望将OS的功能通过网络发布出来。我们考察了一些架构和体系,发现无论是SL还是Flash都无法真实的模拟OS的功能,尤其是在无法确认客户要求的时候,毕竟客户希望获得和OS一样的体验,不仅仅只是文件管理、网络浏览等,可能还有更多的应用需求。如果基于Flash或者SL开发这个平台,就必须为ISV提供一套健壮可靠的基础框架,这种方式的开发成本和应用移植的成本非常之大。很多WebOS的设计思想都是这样的,但是在上面运行的应用程序都是基于BS架构的,客户的应用场景不可能都是BS的,例如Visual Studio就很难做成BS的,虽然编辑器没什么问题但是调试器基本上很难模拟(也不是完全不可行,只是成本和效率不好保证)。当然那这种实现的好处就是运行时需要的资源比较少,SL和Flash都是运行在客户端,服务器端的开销比较少。另外一种可选择的方式就是基于虚拟化技术的VDI,很多公司都有实现,但是也都不是非常完美,一些特殊的场景也不是很好用。Windows Azure是一个好东西,但是它主要提供的是Hosting服务,也无法满足UI及WebOS的功能。MS的终端服务倒是一个能够提供客户端会话的技术,而且开销也相对较少,但是另外一个问题也无法解决,就是无法做到用户的完全隔离,毕竟都是运行在同一个OS上的不同会话,如果操作一些共享的配置及功能例如安装一些软件需要重启。
WebOS的设计就应该提供
- 完整的UI支持
- 对现有应用程序的支持
- 用户环境的隔离和独立
- 如果能够支持多浏览器最好
但是WebOS是永远不会替代本地OS的,因为从安全模型的角度来说无法让远程的代码来控制你本地的资源。其次就是现有的数十万的软件也无法全都移植到WebOS上,虽然SL、FLASH及HTML5已经功能提供的够丰富了,但是本地资源的利用还是本地操作系统实现的更好更简单。
我们的Engine终于可以restart了。
BTW:如果我们的项目发布了,我会在Blog发布体验的地址,大家用Live登录即可。
