数据库选型:曾走弯路现弃用MSSQL等,小场景选C#文件库
1.数据库选型 1.1 概述
读书期间,我经常自己动手捣鼓数据库,回过头来看,确实走了不少弯路。经常是随便什么小事,也要搭建一个庞大的Ms Sql系统,即便是再简单不过的小玩意儿,也非得用mssql。这样的安装不仅耗费了系统资源,而且速度缓慢,部署起来也颇为繁琐。尽管当时用的是盗版软件,但现在回想起来,正是因为自己当时的无知和大学期间知识的不足,加上盲目跟风的指导,我们错过了许多宝贵的学习机会。在近年来的工作实践中,我逐渐舍弃了诸如MSSQL、MySQL等大型数据库系统,这并非意味着它们无法发挥效用,亦非认为它们存在缺陷。只是对于一些较小的问题,使用这些庞大的工具似乎有些大材小用。过分追求细节不仅会让自己感到疲惫,还会对整体工作效果产生不利影响,同时也会造成大量时间的浪费。在较小的应用场景中,我倾向于运用诸如XML等C#文件数据库,而在处理数据量达到亿级及以上的实际需求时,则会选择更为专业的数据库系统。我的目标是确保这些工具能够满足我的使用需求,无需过于复杂或花哨。
1.2 优点
所以说说本项目使用的数据库:,使用它的原因有:
轻量且适用于多平台,该数据库引擎运行于进程内部,无需客户端与服务器之分。仅需引入其动态库,即可解锁所有功能。值得一提的是,该动态库体积小巧,仅几百KB。与之相较,MSSQL的数GB容量,差距显而易见。
绿色版本,独立文件形式。其核心驱动程序无需借助外部软件,无需进行安装操作,这在部署过程中能减少许多繁琐步骤。是否有人安装MSSQL时频繁遇到错误问题?在未安装前,校验过程就无法通过,这实在让人头疼。这也从个人开发成本的角度考虑,想想看,购买几个G的数据库空间需要多少钱,而购买相同容量的硬盘空间几乎可以说是非常便宜。在不影响功能的情况下,何乐而不为;
自2012年开始,我就开始使用XCode组件,对此我深感感激,因为它极大地减轻了我处理数据库相关工作的负担,使我能够专注于业务开发。XCode对Sqlte的支持尤为人性化,对诸多不足之处进行了优化,并且积累了丰富的应用实例。从V9版本起,XCode将引入对网络和分布式数据库的支持,这一新功能将使它更为强大,因而我们有充分的理由去采用它。此外,XCode所具备的灵活分库技术,是我解决查询难题的关键工具。即便我对MSSQL上亿数据的优化并不精通,我依然可以通过分库,以更低的技术门槛和有限的资源来有效应对问题。
1.3 缺点与解决方案
述及了这些长处的同时,或许有人会提出,这些大家早已耳熟能详,然而面对其不足之处,我们又该如何应对呢?实际上,这些问题根本无需过分担忧。
并发性能不尽如人意,这被视为最为关键的难题之一。由于采用单一文件数据库,它可能会在写操作时被独占,进而引发其他读写操作的中断或错误。这一现象不容忽视,我认为有必要在特定情境下对其进行深入分析。在常规时段,项目数据库的读写操作通常不会同时发生,这是因为数据采集与更新的写操作期间,查询分析活动相对较少;再者,即便进行查询分析,由于广泛采用了分库技术,独占资源的情况也相对较少。
关键在于:XCode组件对并发操作进行了特别优化,一旦出现失败情况,会自动进行重试,每次重试间隔300毫秒,最多尝试5次。因此,这种方法能够显著降低数据库锁定错误的发生。再配合恰当的分库策略,这类错误的概率本就极低,即便如此,还有其他应对措施可用。因此,在本项目中,这一难题实际上并不构成问题。关于并发性的相关研究,您可以查阅XCode核心开发者@大石头的文章,其中详细阐述了高并发的研究报告。
在进行网络访问时,有时必须访问位于其他机器上的数据库文件,因此会将这些数据库文件存放在网络共享的目录中。但据称,在并发进行读写操作时,这种做法可能会导致数据损坏的问题。这个问题我之前也曾感到困惑,若公司规模扩大,到那时若考虑采用分布式架构,现有的做法将显得极为不便。通过网络共享目录进行操作,无疑会带来诸多不便与安全隐患。然而,鉴于XCode V9将迎来重大更新,并有望支持网络和分布式数据库,届时我们或许能够实现分布式操作,这些问题便不再是难题。至于处理亿级数据,目前尚不需要依赖网络分布式技术,因此这方面的担忧暂时可以放一放。
2.XCode组件分库技术
这是个人认为本项目非算法的最大的亮点之一。这主要与选择数据库有关,一方面是因为我对数据库的知识掌握不多,难以利用MSSQL轻松处理数千万条数据,包括数据迁移、服务器管理以及大量数据查询的效率问题,这些对于个人来说确实相当棘手。并非无法完成,而是在有限的时间和精力范围内,难以做到更加出色,这也是我选择XCode组件和数据库的主要原因之一。在本项目中,我们将探讨XCode分库技术的具体应用及其带来的益处,以便让大家对这一技术有更深入的了解。
至于X组件的技术文章,可以参考本博客的菜单栏“X组件”。
2.1 分库的目的与场景
在当前项目中,广泛实施分库策略的意图十分明确,旨在简化查询的复杂性,并且有利于数据库的迁移与独立。尤其是在开源环境下,我们能够直接获取各联赛的数据库及各类附加数据,无需单独进行数据导出。鉴于项目累积的历史数据日益增多,且经过前两个版本的测试,附加数据的查询需求极为频繁,故此必须采取分库策略以降低查询的复杂度。在查询单表500万数据时,与从仅含3万条记录的数据库中检索相比,两者之间的性能差异究竟有多大?实际上,我并未亲自进行过测试,但在一些基本情况下,两者所需的时间肯定存在差异,且这种差异可能相当显著。此外,考虑到500万条数据量将会持续增加,而3万条记录的数据量则基本保持不变(因为一旦比赛结束,相关数据便会停止更新,不再增加)。
本项目的分库应用场景极为丰富,以下仅列举数例以作说明,其余内容将在后续的数据库表设计及业务分析阶段逐一阐述。
比赛场次列表以联赛为依据进行分类存储,每个联赛及其杯赛的相关数据均被集中保存在各自的库中。以最多球队的西甲20支队伍为例,一年总共只有380场比赛,十年累计下来也就是3800条记录,因此无论查询技术多么不精湛,速度也不会慢到哪去,何必还要有XCode的缓存功能;在前面两个版本的设计中,我们曾考虑过创建一个总库,但由于实际应用场景尚未充分调研,所以在新版本中数据库尚未加入总库功能。总库和分库的作用是协调互补的,根据实际情况进行。
2.欧赔指数表。足球赛事中,胜平负投注方式尤为普遍,因此欧洲赔率的相关数据尤为丰富。然而,欧赔指数的复杂之处并非每场比赛的实时变动,而在于各家赔率公司所提供的赔率各有差异。赔率公司数量众多,有数百余家,但鉴于实际情况,本系统仅选取了约20家权威机构的数据。此外,数据存储方式也别具一格,为了提高查询效率,我们采用了以赔率公司加联赛为依据的分库策略。
其他指数表中,包括大小盘指数表以及其他各类指数表,均与欧洲赔率类型一致,均采纳了最为适宜当下时刻的数据存储方法。
2.2 分库的方法与使用情况
在XCode里,实现分库操作相当简便,只需对相应的连接字符串进行编辑,完成查询操作时同样需要设定正确的链接字符串。下面将详细介绍设置连接字符串的关键步骤,特别提醒的是,该方法的核心在于对Meat.的修改,而具体的值则需要根据你的分库规则来确定,例如,针对比赛场次表的分库设置:
下面这个是赔率数据的一个分库情况:
在进行数据录入或检索之前,需遵循上述步骤。其他操作流程与你的业务流程完全一致。
3.现有数据库的数据统计情况
鉴于赔率信息的时效性,本系统仅搜集了2013年及以后的赔率资料。至于赛事相关数据,其历史可追溯至十年前。因此,现阶段数据总量尚属有限。然而,随着时间的推移,数据量将逐步增加。为此,我编写了一个简易程序,对当前项目数据库中的数据量及记录进行了统计。
看看核心代码:
//采用键值对方式存储信息,其中键指的是表格的名字,而值则代表具体的记录内容。 Dictionarycount = new Dictionary<string, DbCount>(); //获取文件夹下所有的数据库 var获取指定文件夹内的所有数据库文件,并将结果赋值给变量allDbFiles,具体操作为调用GetAllFilesByFolder函数,传入参数folderName。true); //遍历所有数据库文件 int index = 1; foreach (var item in allDbFiles) { var path = item.ToString(); if (path.Contains("shm") || path.Contains("wal")) continue; //添加数据库连接字符串 DAL.AddConnStr("DbTest", "Data Source=" + item.ToString(), null, "Sqlite"); var dal = DAL.Create("DbTest"); List
tableList = dal.Tables;//获取所有的表 //循环每个表 Console.WriteLine("{0}-{1}",index++,allDbFiles.Count); foreach (var tab in tableList) { IEntityOperate Factory = dal.CreateOperate(tab.Name); int allCount = Factory.FindCount(); if若计数器中不包含表名tab的键,则向计数器中添加键值对,其中键为tab的Name属性,值为新创建的计数。new DbCount(allCount)); else对tab.Name对应的计数器进行累加操作,其RecordCount值增加。 allCount; } if (DAL.ConnStrs.ContainsKey("DbTest")) DAL.ConnStrs.Remove("DbTest"); }
看看统计的结果:
截至2015年5月8日,累计的数据总量达到了743万。这主要是因为历史数据由于时间跨度过长,难以获取(虽然国外可以获取,但过程较为繁琐)。因此,在实际情况的考量下,我们仅收集了2013年及以后年份的主要赔率数据。而之前的数据,我们仅搜集了基本的比赛结果信息。
本文源自叶小钗在数据之巅博客园的博客,原文可点击链接查看,如需进行转载,烦请直接与原作者取得联系。