【原創】C#搭建足球賽事資料庫與預測平台(2) 數據庫與XCode組件


          本博客所有文章分類的總目錄:【總目錄】本博客博文總目錄-實時更新

開源C#彩票數據資料庫系列文章總目錄【目錄】C#搭建足球賽事資料庫與預測平台與彩票數據分析目錄 

  本篇文章開始將逐步介紹使用C#搭建足球賽事資料庫與預測平台的相關細節。還是先從數據庫開始,從本文開始將逐步對每個核心實體類和數據庫設計相關的內容進行講解,並公布源代碼,至於能不能跑起來,看的看個人努力。數據庫很龐大,且采用了XCode非常牛逼的分庫技術,秒殺千萬級乃至上億的數據需求。而只需要最基本的C#技術,對我這種數據庫文盲來說,真的幫助非常大。

  考慮到足球賽事資料庫的復雜性,以及考慮到項目的前瞻性(要考慮到很多還沒有發生的事情,便於以后擴展),以及大量數據,查詢和計算的速度,本項目經歷了3次重構,到目前為止其實也不是很成型,但基本趨於穩定。現在總結起來肯定是很流暢,但這中間的過程非常痛苦,也希望把這些經驗寫出來,有自己做的朋友可以一起探討,避免踩坑。

本文原文地址:【原創】C#搭建足球賽事資料庫與預測平台(2) 數據庫與XCode組件

1.數據庫選型

1.1 概述

  上學的時候,自己折騰數據庫,現在看來其實是走了很多彎路,動不動就搞一個龐大的Ms Sql ,哪怕一個再簡單的東東,也搞一個mssql,安裝不僅占用系統資源,還慢,部署也挺麻煩。。雖然用的是盜版,但其實現在看來,由於自己的無知和大學書本知識的匱乏,盲目的指導,我們失去了很多美好的東西。在近幾年的工作中,我已經逐步拋棄了MSSQL,MySQL這些龐然大物,並不是說他們不能用,或者不好用。只是問題太小,殺雞焉用牛刀。。。小題大作不僅自己累,還影響總體的效果,還會浪費很多寶貴的時間。在一些小的場景下,我會使用一些C#文件數據庫,如NDataBase,XML Database等等,在一些實際數據量在億及級別的情況下,會選擇Sqlite數據庫等等。只要能滿足我的使用要求即可,沒必要搞的那么花哨。

1.2 Sqlite優點

  所以說說本項目使用的數據庫:Sqlite,使用它的原因有:

1.輕量級、跨平台。它是進程內的數據庫引擎,因此不存在數據庫的客戶端和服務器。使用SQLite一般只需要帶上它的一個動態庫,就可以享受它的全部功能。而且那個動態庫的尺寸也非常小,幾百K而已。相比幾個G的 MSSQL,情何以堪;

2.綠色、單一文件。它的核心引擎本身不依賴第三方的軟件,使用不需要“安裝”,可以省去部署時不少麻煩。是不是有人安裝 MSSQL 經常報錯。。沒安裝之前的校驗就通不過。。是不是很坑爹;這個也是處於個人開發成本的考慮,想一想買一個幾個G的數據庫空間啥價格,而買幾個G的硬盤空間簡直就是白菜。。在不影響功能的情況下,何樂而不為;

3.XCode組件的特殊支持。本人12年起開始使用XCode組件,非常感謝它減輕了我很多關於數據庫的東西,讓我只需要關注業務。XCode對Sqlte的支持可以說更加人性化,對很多Sqlite的缺點進行了優化,而且有大量的使用案例。同時XCode在計划的V9版本開始支持網絡和分布式數據庫,這樣Sqlite的功能將更加強大,沒有理由不使用。而且XCode靈活的分庫技術也是解決我查詢問題的重要手段,雖然我不懂MSSQL上億數據的優化,但我可以用分庫,更加低的技術含量和有限的資源來解決問題;

1.3 Sqlite缺點與解決方案

  說完Sqlite的優點,有人可能說,這些誰不知道,但怎么面對它的缺點呢?其實這都不是事。。。

1.不理想的在並發性能。這是Sqlite被認為的最大問題之一,由於是單一文件數據庫,可能會被寫操作獨占,從而導致其它讀寫操作阻塞或出錯。這個問題不能否認,我認為應該單獨放在具體情況中來看。本文的項目數據庫要求在常規時期寫操作和讀操作基本不會同步,因為寫操作是數據采集更新的時候,這個時候是基本不會進行查詢分析的;其次即使查詢分析,由於大量的使用了分庫技術,獨占的情況也會少得多。

  更重要的一點:XCode組件對Sqlite的並發做了特殊處理,如果失敗就重試,間隔300毫秒,一共重試5次。所以這樣可以極大的減少數據庫鎖定的錯誤。加上合理的分庫策略,這種錯誤其實的機率非常低,實在不行,還可以用其他策略。所以在這個項目中,這個問題其實不是問題。至於Sqlite的並發性研究,可以參考XCode的主要開發者@大石頭的文章:SQLite高並發研究報告

2.網絡訪問。有時候需要訪問其它機器上的SQLite數據庫文件,就會把數據庫文件放置到網絡共享目錄上。據說這樣會在並發讀寫的時候會出現數據損壞的問題。這個問題其實以前也困擾我,因為如果以后做大了,考慮做分布式的時候,這樣是非常不便利的,利用網絡共享目錄肯定是諸多不方便和不安全,但考慮到XCode V9會進行重大更新,會支持網絡和分布式數據庫,到時候Sqlite也可以進行分布式操作,這些也都不是問題。至於億級數據,也暫時不需要網絡分布式,所以這個暫時不用擔心。

2.XCode組件分庫技術

  這是個人認為本項目非算法的最大的亮點之一。這和選用Sqlite作為數據庫也有很大關系,一方面本人對數據庫了解較少,無法用MSSQL輕松解決幾千萬數據的問題,數據遷移,服務器管理,大量數據查詢的效率問題,這些對個人來說真的很難辦到,不是辦不到,是在有限的時間和精力下,不能做的更好,這也是選用XCode組件和Sqlite數據庫的主要原因。說一說XCode分庫技術的在本項目中的用法和作用,讓大家也提前開開葷。

  至於X組件的技術文章,可以參考本博客的菜單欄“X組件”。

2.1 分庫的目的與場景

  本項目中大量進行分庫的目的很明顯,減少查詢的復雜程度,同時也便於數據庫遷移和分離,特別考慮開源情況下,可以直接獲取各個聯賽數據庫以及各種附加數據,而不需要單獨進行導出。本項目的由於累積的歷史數據會越來越多,而且經過前2個版本的測試,大量的附加數據查詢非常頻繁,因此必須通過這種方法來減少的查詢復雜度。例如從單表500萬的數據表中,多次查詢數據 和 從單表3萬的數據庫中查,差別會有多少?當然我沒測試過,簡單情況下,時間總歸是有差別的,應該也不小,而且500萬數據是要增長的,而單表3萬是基本不會增長(因為一場比賽結束了,相關數據就終止了,不會再增加)。

  本項目的分庫場景非常多,這里舉幾個例子說明,其他的在具體的數據庫表設計和業務分析的時候再進行說明。

1.比賽場次表。比賽場次表按照聯賽進行分庫,每一個聯賽或者杯賽,的數據都保存在一起。按照最多球隊的西甲20支隊伍來說,一年也就380場比賽,10年也就3800條記錄,所以怎么查,技術再差,也不會慢到哪里去,何苦還有XCode的緩存支持;在前2個版本的設計中,還考慮過設計一個總庫,但由於實際的使用情況場景還有待考察,所以新版本的數據庫還暫時沒有添加總庫。總庫和分庫的作用是協調互補的,根據實際情況進行。

2.歐賠指數表。勝平負的玩法是足球比賽中最常見的,所以歐賠的數據也是最多的,歐賠指數的復雜性不在於每一場比賽會動態調整,而在於每一場比賽,每一個家賠率公司開出的賠率都不一樣,賠率公司多大幾百家,考慮到實際情況,本系統只采集了權威的20家左右,分庫方式也很特別,為了獲得查詢的效率,按照 賠率公司 + 聯賽 的方式進行分庫。

3.其他指數表。大小盤指數表和其他指數表與歐賠類型,都采用了 最符合時間的 分庫方式。 

2.2 分庫的方法與使用情況

   在XCode中,分庫是非常簡單的事情,只需要修改對應的連接字符串,就可以了,查詢之前也設置對應的鏈接字符串就可以了,下面就是核心的設置連接字符串的方法,注意方法的核心是修改Meat.ConnName,至於值取決你分庫的標准,如下面的比賽場次表的分庫:

下面這個是賠率數據的一個分庫情況:

   只需要在插入數據或者查詢數據前,執行上述方法就可以了。其他操作和你的業務是一模一樣的。

3.現有數據庫的數據統計情況

  由於賠率數據的時效性,本系統也只采集了2013年以后的賠率數據,至於場次數據,可以追溯到10年前。所以暫時來說數據量不是很大,隨着累計的時間越來越長,數據的增長會越來越快。寫了一個簡單的程序對現在項目的數據庫的數量和數據記錄做了一下統計:

 看看核心代碼:

//按照key-vale存儲數據,key為表名稱,value為記錄對象
Dictionary<String, DbCount> count = 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<IDataTable> 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 (!count.ContainsKey(tab.Name)) count.Add(tab.Name, new DbCount(allCount));
        else count[tab.Name].RecordCount += allCount;
    }

    if (DAL.ConnStrs.ContainsKey("DbTest")) DAL.ConnStrs.Remove("DbTest");
}

看看統計的結果:

截至2015年5月8日,總的數據量是:743萬。主要原因是一方面歷史數據過了太長時間采集不到(國外可以,但是麻煩)。所以考慮到實際情況,只采集了2013年以后的主要賠率數據。以前的數據只采集基本的比賽結果信息。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM