SVS 没有尽头

SVS is SQL & Visual Studio
随笔 - 9, 评论 - 8, 引用 - 0

导航

工具

关于

做技术的路没有尽头,你只能看到前方几公里,但是更远的地方总是看不太清,当远处的景色渐渐清晰,回首看,有我们深深的足迹。兄弟们,上路吧,前方还有更多的难关,也有更美的景色。

每月存档

广告



访客

2008年12月23日

前几天在客户那里安装SQL Server 2008 Active/Active Cluster的时候遇到一些小问题,这里总结一下,因为SQL Server 2008的Cluster安装方法已经和2005非常不同了,而且第一次安装的时候还没装成功,因为那个时候还是RC0的版本,产品组的人告诉我就根本装不上,所以这次安装的时候特别的小心。

SQL Server 2008安装的过程与之前的版本完全不一样了,提供了一个特殊的工具用于安装,因为之前的安装经常出现一些怪异的问题,尤其是在Cluster安装的时候。在前版本的Cluster安装只需要在一个节点安装一次就可以将一个SQL实例安装到多个节点上,这样随然看起来比较方便,但是安装的过程相对较慢,而且非常容易出错,主要是因为为了保证2个节点安装同时成功,需要启动MSDTC来提供事物保证,而在安装的过程中需要安装各种组件例如.net framework,native client ,MSXML等,这样多的组件中止要有一个出现问题都会产生影响,而且安装的时间也没有一个很好的评估。一般我都先分别在节点上装好需要的组件,然后在安装,而且安装的过程中不要包含那些不必要的组件,例如管理工具之类的。

在SQL Server 2008的Cluster安装中,安装的方法发生了变化,将原有的1次安装多个节点改为1次只安装一个节点,这样做得好处是将事物边界缩小,这样出错的概率会比较低(事物尽可能短小,是不变的真理),安装完成一个节点后,在安装另外一个节点的时候选择加入群集,就可以了。

在安装A/P Cluster的时候没有问题,但是在A/A的时候,会遇到一些小问题,这个问题已经有了明确的说明-bug,在SQL Server 2008 CU1中提供的修正。当你安装完成一个实例的Cluster后,在另外一个节点安装第2个实例,这次还是还是选择安装新的cluster节点,这个安装也不会遇到问题,当你在第一节点加入第2实例时,会遇到一个SKU Error,此时需要在第一节点安装CU1,然后再添加第2实例。

当安装完成后,还需要在2个节点上各安装一次CU1,否则实例中的SQL Server版本将不一样,以后应用的时候可能会有问题。

所以A/A Cluster安装会非常麻烦,安装4次SQL Server,安装3次CU1.

 

posted on 2008-12-23 10:24:52 by Sun.wei  评论(1) 阅读(2153)

 
2008年11月11日
好久没有写文章了,有时候想写点东西但是又不知该写点什么。总觉得微软的技术不错,但是就是更新的太快,也许我们也老了。很多人还在用VS2003写东西,因为他们觉得够用了,而且升级到VS2008上,大家也都不能确定会有多少Code需要重构,所以还沿用至今。
最近一直在关注ASP.NET MVC的东西,感觉微软有后发制人的想法,虽然明年才能发布(也不知道会不会跳票,估计是等VS一起发布)但是现在但是可以用这个东西做点事情了,毕竟ASP.NET MVC中很多思想和模式都已经渐渐成熟了,个人觉得这是个好东东,但是需要更多的指导手册。在ASP.net站点上有一套screencast不错,将一个完整的MVC应用的设计开发过程都展示出来,而且有Code可以下载学习。
很多初学者会发现Route是一个不好搞定的东东,默认情况下新建的ASP.NET MVC项目会建立Controller/Views/Models目录,但是大多数情况下,我们的应用结构肯定不是这个样子的例如
WebApp/
WebApp/Areas/
WebApp/Areas/HR
WebApp/Areas/HR/Controller
WebApp/Areas/HR/Views
WebApp/Areas/HR/Models
WebApp/Controller
WebApp/Views
WebApp/Models
这样规划开起来更清晰,但是需要我们对于Route做一些特殊的处理,我们需要对于Controller和View做相应的扩展,因为我们的View中页面和空间的位置以及Controller的名称空间都发生了变化。我们需要做一个自定义的WebFormViewEngine并扩展RouteCollection对于Controller映射方法

在WebFormViewEngine中我们需要重载FindPartialView和FindView方法,以便于MVC在Render的时候可以找到相应的.ascx和aspx。在扩展RouteCollection是主要是需要重新映射Controller的名称空间。
接下来只需要在Global.asax.cs中使用MapAreas和MapRootAreas注册你的Route,并ViewEngines.Engines中添加我们的的WebFormViewEngine 就可以了。

下面是相应的代码片段
    public class AreaViewEngine : WebFormViewEngine {
        public AreaViewEngine() : base() {
            ViewLocationFormats = new[] {
                "~/{0}.aspx",
                "~/{0}.ascx",
                "~/Views/{1}/{0}.aspx",
                "~/Views/{1}/{0}.ascx",
                "~/Views/Shared/{0}.aspx",
                "~/Views/Shared/{0}.ascx",
            };

            MasterLocationFormats = new[] {
                "~/{0}.master",
                "~/Shared/{0}.master",
                "~/Views/{1}/{0}.master",
                "~/Views/Shared/{0}.master",
            };

            PartialViewLocationFormats = ViewLocationFormats;
        }

        public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName) {
           
            ViewEngineResult areaResult = null;
           
            if (controllerContext.RouteData.Values.ContainsKey("area")) {
                string areaPartialName = FormatViewName(controllerContext, partialViewName);
                areaResult = base.FindPartialView(controllerContext, areaPartialName);
                if (areaResult != null && areaResult.View != null) {
                    return areaResult;
                }
                string sharedAreaPartialName = FormatSharedViewName(controllerContext, partialViewName);
                areaResult = base.FindPartialView(controllerContext, sharedAreaPartialName);
                if (areaResult != null && areaResult.View != null) {
                    return areaResult;
                }
            }
           
            return base.FindPartialView(controllerContext, partialViewName);
        }

        public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName) {

            ViewEngineResult areaResult = null;

            if (controllerContext.RouteData.Values.ContainsKey("area")) {
                string areaViewName = FormatViewName(controllerContext, viewName);
                areaResult = base.FindView(controllerContext, areaViewName, masterName);
                if (areaResult != null && areaResult.View != null) {
                    return areaResult;
                }
                string sharedAreaViewName = FormatSharedViewName(controllerContext, viewName);
                areaResult = base.FindView(controllerContext, sharedAreaViewName, masterName);
                if (areaResult != null && areaResult.View != null) {
                    return areaResult;
                }
            }
           
            return base.FindView(controllerContext, viewName, masterName);
        }

        private static string FormatViewName(ControllerContext controllerContext, string viewName) {
            string controllerName = controllerContext.RouteData.GetRequiredString("controller");

            string area = controllerContext.RouteData.Values["area"].ToString();
            return "Areas/" + area + "/Views/" + controllerName + "/" + viewName;
        }

        private static string FormatSharedViewName(ControllerContext controllerContext, string viewName) {
            string area = controllerContext.RouteData.Values["area"].ToString();
            return "Areas/" + area + "/Views/Shared/" + viewName;
        }
    }

public static class AreaRouteHelper {
        public static void MapAreas(this RouteCollection routes, string url, string rootNamespace, string[] areas) {
            Array.ForEach(areas, area => {
                Route route = new Route("{area}/" + url, new MvcRouteHandler());
                route.Constraints = new RouteValueDictionary(new { area });
                string areaNamespace = rootNamespace + ".Areas." + area + ".Controllers";
                route.DataTokens = new RouteValueDictionary(new { namespaces = new string[] { areaNamespace } });
                route.Defaults = new RouteValueDictionary(new { action = "Index", controller = "Home", id = "" });
                routes.Add(route);
            });
        }

        public static void MapRootArea(this RouteCollection routes, string url, string rootNamespace, object defaults) {
            Route route = new Route(url, new MvcRouteHandler());
            route.DataTokens = new RouteValueDictionary(new { namespaces = new string[] { rootNamespace + ".Controllers" } });
            route.Defaults = new RouteValueDictionary(new { area="root", action = "Index", controller = "Home", id = "" });
            routes.Add(route);
        }
    }
具体的可以参考 http://haacked.com/archive/2008/11/04/areas-in-aspnetmvc.aspx

posted on 2008-11-11 14:24:52 by Sun.wei  评论(0) 阅读(3960)

 
2008年06月19日

好久没有些东西了,好像大家最近都很忙,写东西的人不多。最近事情真的很多,国家大事多,体育赛事多,。。。。

SQL Server 2008 RC0已经发布了,但是我还没有去download呢,因为再等新机器,T61P,装了x64的系统,装SQL当然也要x64的,所以要等等。SQL Server 2008很多人都还没有用过,Webcast上倒是已经有很多课程了,大家可以去学学,很多新的功能还是不错的。我最近一直在做关于FileStream的东西,好多人也会有这种疑惑,为什么要把Blob数据,通俗的讲就是文件为什么要存储到数据库里,存到文件系统不是也很好吗?So.......美国人说话总是说So,大家可以想一个问题,如果你的文件很多,比如有N TB数据怎么办?还放到文件系统里吗?当然可以,放到哪里有你决定,但是文件很多的时候管理成本就会增加,而且存储成本也将不断的增加,客户需要一种文件管理的系统。Windows的文件管理并不是十分的好,如果你的一个文件夹中有数百万文件,估计这个文件夹也没办法展开了。多年前,我们还在用Windows XP&Windows Server 2003时,MS给了我们一个Idea-WinFS,新的文件管理平台,用数据库去管理文件系统,几百万条记录的检索在数据库中并不是很慢,至少不会像explorer一样死掉。但是遗憾的是在Vista中并没有发布这个东西。

在SQL Server  2008中的FileStream特性给我们提供了这样一个可能,就是WinFS,换个马甲我还认得,哈哈哈。我们可以把Blob数据存储到SQL Server中,当然数据空间并不是在传统的MDF中,还是在文件系统里,只不过我们可以通过SQL Server来进行管理,这样检索数据就会相对简单很多了。我们的这个客户Blob数据量估计在60T左右,按每个文件2MB,3千万个文件。千万级数据的查询应该不会太慢,因为我们没有什么关联的表。

但是MS的想法更大,一个大想法,RBS,Remote Blob Storage,也就是远程Blob存储系统,这个比WinFS的概念可就大多了,这个RBS就是希望通过利用更多小型的存储系统去替代那种昂贵的大型存储系统。当然这个RBS是一个Provider的模式,可以通过自己开发Provider来去实现各种存储的方式,可以存储到磁盘、磁带、数据库中,我们现在就是要做一个RBS Provider for SQL Database并且带有NLB的功能。这个大想法给用户带来的好处就是他们可以用统一的应用程序接口来去访问文件,而并不用关系文件存储的位置和存储系统,我们可以将数据存储在Near Line系统中当然这样的系统动不动就几个Million的$,也可以有一种选择放到数据库里面,当然通过RBS Client中我们就不用去知道后面这些东西怎么处理了,只要我们传一个StoreBlobId给RBS就可以了,我们通过自己实现的Provide算法去返回给客户端。RBS这个东西的目的很明显用SQL Server实现文件管理,当然这个是MS的目标,database这个词开始的时候就是做管理文件的,当然用RBS去连接其他的存储系统也是可以的,因为Provider的模式还是比较灵活的。这个东西还不知道是不是在SQL Server RC0中包含,但是RBS Client的代码是已经Completed。

以前我都很少研究Storage这个东西,毕竟好像和应用开发和数据库还有些距离,但是RBS这个就是介于Storage和App之间的一个桥梁,对于很多特殊的用户来说是非常有意义的,毕竟存储这个东西还是很贵的。

posted on 2008-06-19 14:34:56 by Sun.wei  评论(3) 阅读(4498)

 
2008年05月19日

最近可能要做一个项目,规模不小,但我负责的部分不大,就是开发一些管理工具,用于对Partition和FileGroup的管理。

用户的这个数据库就是用于管理文件的,但是数量相当的大,预估每天在60G左右, 在使用FileStream的时候就要考虑一下了。本身FileStream就是Varbinary的数据类型,我们可以使用T-SQL语句进行操作,也可以使用Win32 API(那天听说了一个新名词RBS-Remote Blob Storage),这样一来我们如何确定适用那种方式进行操作就成了问题。

如何选择主要要看数据的大小了,一般来说如果数据小于2M的使用使用T-SQL的方式会比较快一些,如果数据大小大于2M Win32 API会快一些,另外还要注意的就是Win32 API不支持部分更新,也就是说无法进更新varbinary中部分的数据,所以选择以何种方式使用Filestream的时候也要注意。

另外在还要注意的是我们在更新数据byte的的时候都会有一个缓存的数组,这个数组的大小对于性能也有很大的影响,这个大小最好能够与磁盘扇区的大小对齐,在之前我的代码中512和4096时的性能差异就很大了。

posted on 2008-05-19 16:03:13 by Sun.wei  评论(0) 阅读(3792)

 
2008年05月14日

5.12地震,我正在成都出差,正当讲课的时候,地震了。稳住情绪后和学员一起逃生。经历的这场恐怖的地震后,发现地震并不可怕,真正可怕的来自于自己内心的恐惧和孤独,另外还要不出一些专业知识。我总结了一些经验给大家共享一下:

  1. 不要恋财,逃命要紧,只要拿上必需的钱和手机即可,其他的以后再说
  2. 手机上设置好紧急拨号的功能,1键拨出去。
  3. 有机会要买些水和士力架,我就忘了士力架了,本来包里有的,出来时候让我拿出去了,但是水一定要有,没水人坚
  4. 不了多久,士力架主要是糖和巧克力对于补充体力来说很有效,毕竟你不能背着葡萄糖的瓶子到处跑
  5. 找空旷的地方,酒店不要太高,也不要太低。高层的基本逃不出来,低的一般设计上不结实
  6. 注意使用电梯的时机,并且每到一个地方先看好紧急出口在那里,有条件的先走一遍,这样逃得时候才能最快的找到出路。
  7. 不要到人员聚集的地方,人多地地方不一定安全,人多的地方经常遇到情况的时候会很混乱,可能没被震死,会被踩死
  8. 远离加油站、电线杆、隧道、山坡、水渠、化工厂,那里可能会有其他的危险
  9. 保持通讯,有机会就找地方给手机充电,虽然手机不一定都好用,但是也许能用于求救
  10. 通过各种渠道及量多地从外面获取消息,本地的消息你很难及时得到,这里机场和航空公司的电话根本打不进去
  11. 有机会就去提款机拿点现金,很多地方不能刷卡的,现金更管用
  12. 保持冷静,如果恐惧就给别人打电话,这样冷静下来能让你更灵敏,头脑清醒非常重要
  13. 保持体力,不要瞎跑,能休息时尽量找安全地方休息,也许下一秒需要你来一个冲刺才能逃出去,另外安全的时候找机会睡一下,因为更多地时候都是出于神经紧张的状态
  14. 抽烟的人,多准备点烟,这个东西可以让你放松一下,可以自己安抚一下恐惧的心情,不抽烟的就准备口香糖。或者找点其他的事干,当然干工作都没心情了,但是要想办法击退自己内心的心魔
  15. 最后一点最重要了,保持冷静,自己不要乱了方寸,能战胜自己就是胜利,心魔是你自己,战胜它不难,但要有意志力。遇事切勿慌张,要有自己的想法,切勿不自己思考跟着别人走,那样你的命运就不再你手上了

还有主要的恐惧不是来源于那次主震,而是接连不断的余震,震动的不是大楼,而是震得是你的心,不断地折磨你,摧毁你的意志,说不怕都瞎扯。所以要不断地给自己信号,冷静没什么事了。

目前本人还没有出来呢,但情况还好,可以接受了。就是睡觉不踏实,经常感觉有震动,由于神经高度紧张,有点像地动仪了。原来准备继续写的文章也都推迟了,等我从成都回去再说了。

God save me.

posted on 2008-05-14 15:11:51 by Sun.wei  评论(2) 阅读(4495)

 
2008年05月08日

Scalability对于软件设计师来说永远都是一种挑战,虽然我们设计的系统并不一定都要有Scalibility的能力但是客户往往都有这方面的期待,因为每个客户都希望自己的业务能够做大,都希望自己的数据库可以与Myspace一样大。最近要和lvke兄弟合作写一些对于数据库的东西,这里也和大家分享一下自己的体会。

Session 1

What is Scalability?

 扩展性就是说我们需要让应用程序可以使用更多的资源去做更多的工作。简单的说就是随着业务增加,应用程序将承担更多的负载,这个时候我们需要对于应用程序使用的资源进行调整,用来处理这些负载,这是我们的应用程序能否有能力的利用这些增加的资源,这就是Scalability。

对于应用程序来说,我们可通过减低组件的耦合程度将组件分层并部署到不同的服务器上,同时考虑每层组件对于NLB的支持,这样就可形成一个云,每层服务组件都可能由若干服务器来运行,当负载增加时可以通过增加服务器的方式来进行横向的扩展,多数的互联网企业都是这种思路。

对于Scalability来说,通常用2种方式实现-Scale Up和Scale Out。对于不同的环境和要求来说,正确的使用相应的策略才是最关键的。Scale up就是提供更强大的服务器来提供更好的性能,如果你的软件系统可以支持更多的CUP和内存,Scale up也是一个不错的方式。但是目前的服务器的处理能力受到很多技术上的限制,并不是说我们可以无限制的添加资源,同时我们的软件系统也并不一定可以支持这么多的CPU和内存,不论你是Windows或Unix。同时更大的服务器也意味着更高的成本。这时人们更多的是想到Scale out的方案。Scale out方案就是利用N个廉价的服务器去处理更多的业务,业务增加时可通过增加服务器来实现业务的处理,这样从理论上我们可以不去限制服务器的数量,互联网应用就是典型的Scale out,当然互联网行业有他特定的行业特点。

应用程序中很多情况下离不开数据库的支撑,除非你是Google,有能力自己去编写适应与自己业务的数据库。通常情况下我们都会采用一些商业或开源的数据库产品来实现我们对于数据持久和查询的功能。我遇到了很多客户在进行产品选型的时候都会说我们要求你们的数据库可以实现负载均衡等类似的要求,大家也都知道数据库上的均衡方式不同于我们Web服务器的均衡,我们要考虑到数据的同步、事务等更多的方面。长期以来很多用户都在诟病SQL Server无法做到Load Balance,而Oracle的RAC却可以实现。我稍微看了一下Oracle的RAC,从原理上他也无法实现类似于服务器云的那种形态,因为RAC其实是一个Cluster,需要共享网络总线和磁盘系统,网络总线用于同步Cache,共享SAN用于存储数据。SQL Server虽然也能实现Cluster,但是A/A群集上的2个实例还是无法做到对于性能有什么提升。当然RAC也不是没有缺陷,当节点数大于2个的时候性能并不是按照我们想象的一样按照线形增长,而且当节点数持续增加的时候网络可能就会成为最大的瓶颈,而且在国内目前看到的RAC也只是以2个节点的为多,更多节点的RAC目前在国内也没有太多成功的案例。回来继续谈谈SQL Server,虽然By default,没有RAC的功能,但是并不是代表不能做到,MySpace有数百台SQL Server支撑网站,形成一个数据库服务器云,可以通过增加数据库服务器来支撑用户数量的增加,还有像纳斯达克这样的应用场景也都是存在类似的方案。所以说能和不能并不是重要的,系统地架构设计+产品的功能也能帮我们实现数据库服务器的Scale out。

目前我们在SQL Server上的Scale out Solutiion主要有以下几种

  • Scalable Shared Database
  • Peer-to-Peer Replication
  • Linked Servers and Distributed Queries
  • Distributed Partitioned Views(DPV)
  • Data-Dependet Routing
  • SOA

后续的文章我会慢慢的聊聊这些Solution,时间所限可能会很慢很慢很慢。。。。

posted on 2008-05-08 15:14:48 by Sun.wei  评论(2) 阅读(4792)

 
2008年04月09日

又快有1个月没写东西了,不是因为懒,而是忙于学习。ASP.NET MVC Preview 2已经发布一段时间了,在网上看到了一些相关的文章,但是由于是Preview的版本,没有SDK,学习很辛苦。很多文章都讲了Route的用法,Google一下太多了。但是我遇到了一些问题却始终没有找到答案,先在这里分享一下,看看大家有没有更好的方法。

我们在做一个web app的时候,通常会有很多的模块,例如MIS系统,里面会有CRM\HR等,这时再进行构架的时候,就会出现这样一个问题可能在不同的模块中都会有HomeController,当然我们可以在Project中添加文件夹,并使用不同的名称空间来解决,而且在URL上也可以自己添加Route来搞定。这些在Google都能找到解决方案,但是在View层的问题就麻烦了。类似于Controller,不同的模块都有Index视图,而默认情况下视图是依赖于文件系统的,而且还有。。。(下面说),view code 先,

 public class WebFormViewLocator : ViewLocator {
        public WebFormViewLocator() {
            ViewLocationFormats = new[] {
                "~/Views/{1}/{0}.aspx",
                "~/Views/{1}/{0}.ascx",
                "~/Views/Shared/{0}.aspx",
                "~/Views/Shared/{0}.ascx"
            };
            MasterLocationFormats = new[] {
                "~/Views/{1}/{0}.master",
                "~/Views/Shared/{0}.master"
            };
        }
    }

这个部分是MVC中WebFormViewLocator的构造函数,大家可以看出一个问题在,在Controller中调用RenderView的时候你只能指定View的Name,然后默认情况下WebFormViewEngine会调用IViewLocator的GetViewLocation方法,这个时候传入的参数就是viewContext和viewContex.ViewName,所以如果你的View没有按照这个格式保存在相应的目录中就会出现问题。

Code看过了,那问题就来了应用稍微复杂一些,我们的View就会有很多了中不能按照这种发式进行开发呀。

接下来又要仔细的看看Source Code了,ViewLocator在GetPaht函数中调用了一个IsSpecificPath的函数

        private static bool IsSpecificPath(string name) {
            return
                name.StartsWith("~", StringComparison.Ordinal) ||
                name.StartsWith("/", StringComparison.Ordinal);
        }

这回看明白了,只要在RenderView的时候按照这个规则写上路径就可以了,当然要添加.aspx后缀名。

没有SDK的日子。。。。。。

posted on 2008-04-09 13:56:31 by Sun.wei  评论(0) 阅读(3563)

 
2008年03月14日
昨天SQL Server 2008发布了,很多用户目前还没有用上SQL 2005,产品真是太快了,看样子学习的步伐也要加快了。这2天看了看SQL 2008的新功能,发现和05的版本相比功能是增加了一些,但是没有什么本质上的区别,只不过对于某些特殊的应用场景有了很好的优化。其中在数据类型上提供了几个新的数据类型,这里我们就先聊聊Filestream。
其实对于很多开发人员来说如何存储BLOB的数据一直就是一个麻烦的事情。原来可选方案只有2中,将BLOB保存在SQL Server中的Image或者Text数据类型中,2进制数据放到SQL的数据文件中;另外就是将数据放到文件系统上,然后将文件的地址保存在数据库中。这2中方法各有利弊。在文件系统中的2进制数据在管理上相对比较麻烦,因为要保证对于数据的修改必须在文件系统和数据库中同时完成,或者可以说需要在一个事务中完成,这里还要注意的就是文件系统可不支持Transaction,而且这些文件也无法收到保护,其他用户可能会误操作删除文件。保存在数据库中的主要问题是性能,因为所有对于这些BLOB字段的操作也会占用Cache,而且这些Cache其实很难复用,有些浪费了,另外在BLOB字段中的数据长度最大只能有2G。
FileStream就可以解决这些问题,Let’s go. Do it.
首先我们先需要在数据库引擎上开启FileStream Access,默认是禁用的。在Feb的CTP中 BOL上有一个地方写错了,@enable_level=2,我查了一下这个值的范围在0-2,BOL上写的是3,需要更正。
sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
exec sp_filestream_configure@enable_level=2;
GO
RECONFIGURE;
GO
 
然后需要shutdown 数据库,重新启动服务
接下来就是创建数据库并指定Filestream的文件组,同时创建表。
create database FSPhoto
on
primary
(name=PhotoData,FILENAME='D:\Code\SQLDB\PHOTO.mdf'),
FileGroup FileStreamGroup1 Contains
Filestream(Name=PhotoFile,FILENAME='D:\Code\SQLDB\Photo')
log on(Name=PhotoLog,FILENAME='D:\Code\SQLDB\PHOTO.ldf')
go
use FSPhoto
go
create table Photos
(
ID uniqueidentifier RowGuidCol not null unique,
Name nvarchar(50) not null,
FS varbinary(max) filestream null
)
go
接下来我们就开始使用了。你可以先去相应的文件夹看看,系统会创建出一些目录和文件,里面的.hdr文件是个系统文件,不要使用工具将其打开。
在Insert的时候我们通常需要提供一个展位符,这样我们才能获取相应文件在系统中的句柄,这点和之前版本中的Textptr函数差不多。
declare @id uniqueidentifier
select @id=NEWID()
insert photos values(@id,'aaa.jpg',cast('' as varbinary(max)))
select @id
这里要注意的是’’和null是不一样的,null不会再文件系统中创建文件也就是在后面我们无法获取句柄,而’’是创建了空文件,文件是空的但是有句柄。
select FS.PathName() from Photos where id =@id
你就可以看到这个文件的路径。
因为这个路径是受到SQL Server保护的,我们有那个File类无法获取。所以需要使用一个函数
[DllImport("sqlncli10.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern SafeFileHandle OpenSqlFilestream(string FilestreamPath,
            UInt32 DesiredAccess,
            UInt32 OpenOptions,
            byte[] FilestreamTransactionContext,
            UInt32 FilestreamTransactionContextLength,
            Int64 AllocationSize);
使用这个函数去访问文件。除了这个函数之外还有一个重要的语句
select GET_FILESTREAM_TRANSACTION_CONTEXT()
这个语句就是可以将OpenSqlFilestream函数的操作与SQL的操作绑定在一个transaction中。这样就可以了。剩下的操作就是用构造一个FileStream类然后在构造函数中将OpenSqlFilestream的结果传入,然后就简单了。

posted on 2008-03-14 15:08:03 by Sun.wei  评论(0) 阅读(2734)

 
2008年03月11日

好久没有写技术的Blog了,幸好开心给我提供了这个空间能和大家多多的交流,废话少说,直接进入主题。
最近做了一个关于SQL的项目,用户对于高可用性要求相当的高,在这个项目上基本上把SQL Server 2005能用到的高可用技术都用上了,主要就是Cluster+Mirroring+LogShipping+Replication,当然这些也都是根据不同的子系统对于可用性要求的SLA来设计的,其中比较复杂和麻烦的是设计Replication。
其实从Replication的角度来说,最常用的就是这个Transaction Replication,其基本的原理就是先基于BCP做一套相应发布数据的快照,后续的就是启动Log Reader Agent来读取发布数据库的事务日志,然后将操作传递到分发服务器上,再有分发服务器推送给订阅服务器,过程虽然不是很复杂,但是需要调整的参数是相当的多。
在这个方案中主要遇到了2个小问题,一个是关于BLOB字段的复制,另外一个就是对于同步数据时一个特殊的需求,这个我在下一次会具体说明。
BLOB的字段在很多应用上会用到,很多人在开发应用的时候都与Image和文档的数据都是保存在文件系统上,这样做是最简单的,但是查询起来就会比较麻烦了,放到数据库中可以使用SQL的Full Text Search,这样检索文档中的信息就会比较容易了。但是问题在于如何将一个大的文档保存到数据库上。我们通常的做法是创建一个BLOB的字段,在SQL Server中可以使用Image、Text、varbinary(max)等,很多人还在使用SQL2000上的模式,也就是使用Image和Text。在使用Image和Text的时候主要是会使用WriteText、UpdateText、TextPtr这3个函数,然后将从文件读到流分割后批量写入的SQL中,当然注意一点这些函数在SQL的后续版本中可能会删除,用其他的函数代替。还有一点就是最好能将分割的数据长度设置为8060,这样插入的速度可以更快一些。回到主题上吧,在Transaction Replication的环境中原有的这种方式就会出问题,问题出在Transaction上。如果不将插入图片的所有操作设计为一个Transaction中,每一个操作都会是一个独立的事务复制到订阅端,在订阅端执行的时候TextPtr函数的结果是不同的。如果在一个Transaction中,其实就是将这边的操作做为一个整体复制到了订阅端,这样才能保证指针位置的正确性。

posted on 2008-03-11 09:18:05 by Sun.wei  评论(0) 阅读(1789)

 

Powered by: Joycode MVC Blogger System