搜尋
首頁資料庫SQL學習在SQLServer中處理千萬單位記錄

sql教學欄位介紹如何處理千萬單位的記錄。

學習在SQLServer中處理千萬單位記錄

推薦:sql教學

專案背景

這是給某資料中心做的一個項目,項目難度之大令人髮指,這個項目真正的讓我感覺到了,商場如戰場,而我只是其中的一個小兵,太多的戰術,太多的高層之間的較量,太多的內幕了。具體這個專案的情況,我有空再寫相關的博文出來。

這個專案是要求做環境監控,我們暫且把受監控的設備稱為採集設備,採集設備的屬性稱為監控指標。專案需求:系統支援不少於10w個監控指標,每個監控指標的資料更新不大於20秒,儲存延遲不超過120秒。那麼,我們可以透過簡單的計算得出較理想的狀態-要儲存的資料為:每分鐘30w,每個小時1800w,也就是每天4億3千兩百萬。而實際,數據量會比這個大5%左右。 (其實大部分是資訊垃圾,可以用資料壓縮處理的,但是別人就是要搞你,能咋辦)

上面是專案要求的指標,我想很多有不少大數據處理經驗的同學都會呲之以鼻,就這麼點?嗯,我也看了很多大數據處理的東西,但是之前沒處理過,看別人是頭頭是道,什麼分佈式,什麼讀寫分離,看起來確實很容易解決。但是,問題沒這麼簡單,上面我說了,這是一個非常惡劣的項目,是產業惡性競爭典型的項目。

  1. 沒有更多的伺服器,而是這個伺服器除了搭配資料庫、集中採集器(就是資料解析、警告、儲存的程式),還要支援30w點的北向介面(SNMP),在程式沒有最佳化之前CPU常年佔用80%以上。因為專案要求要使用雙機熱備,為了省事,減少不必要的麻煩,我們把相關的服務放在一起,以便能夠充分利用HA的特性(外部購買的HA系統)
  2. 系統數據正確性要求極為變態,要求從底層採集系統到最上層的監控系統,一條數據都不能差
    我們的系統架構如下,可以看到,其中數據庫壓力非常之大,尤其在LevelA節點:
  3. 硬體配置如下:
    CPU:Intel® 至強® 處理器E5-2609 (4核心, 2.40GHz, 10MB, 6.4 GT/s)
    記憶體:4GB (2x2GB) DDR3 RDIMM Memory, 1333MHz,ECC
    硬碟:500GB 7200 RPM 3.5'' SATA3 硬碟,Raid5.
  4. 資料庫版本
    採用的是SQLServer2012標準版,HP提供的正版軟體,缺少許多企業版的NB功能。

推薦自己的linuxC/C 交流群:973961276!整理了一些個人覺得比較好的學習書籍、視頻資料以及大廠面經視頻共享在群文件裡面,有需要的小伙伴可以自行添加哦! ~

寫入瓶頸

首先遇到的第一個攔路虎就是,我們發現現有的程式下,SQLServer根本處理不了這麼多的資料量,具體情況是怎樣的呢?

我們的儲存結構

一般為了儲存大量的歷史數據,我們都會進行一個物理的分錶,否則每天百萬筆的記錄,一年下來就是幾億筆。因此,原來我們的表格結構是這樣的:

CREATE TABLE [dbo].[His20140822](
    [No] [bigint] IDENTITY(1,1) NOT NULL,
    [Dtime] [datetime] NOT NULL,
    [MgrObjId] [varchar](36) NOT NULL,
    [Id] [varchar](50) NOT NULL,
    [Value] [varchar](50) NOT NULL,
 CONSTRAINT [PK_His20140822] PRIMARY KEY CLUSTERED (
    [No] ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY]

No作為唯一的識別、採集設備Id(Guid)、監控指標Id(varchar(50))、記錄時間、記錄值。並以採集設備Id和監控指標Id作為索引,以便快速找到。

批次寫入

寫入當時是用BulKCopy,沒錯,就是它,號稱寫入百萬筆記錄都是秒級的

    public static int BatchInert(string connectionString, string desTable, DataTable dt, int batchSize = 500)
    {
        using (var sbc = new SqlBulkCopy(connectionString, SqlBulkCopyOptions.UseInternalTransaction)
        {
            BulkCopyTimeout = 300,
            NotifyAfter = dt.Rows.Count,
            BatchSize = batchSize,
            DestinationTableName = desTable        })
        {
            foreach (DataColumn column in dt.Columns)
                sbc.ColumnMappings.Add(column.ColumnName, column.ColumnName);
            sbc.WriteToServer(dt);
        }

        return dt.Rows.Count;
    }

有什麼問題?

上面的架構,在每天4千萬的資料都是OK的。但是,調整為上述背景下的配置時,集中監控程序就內存溢出了,分析得知,接收的太多數據,放在了內存中,但是沒有來得及寫入到數據庫中,最終導致了生成的數據大於消費的數據,導致記憶體溢出,程式無法運作。

瓶頸到底在哪裡?

是因為RAID磁碟的問題?是資料結構的問題?是硬體的問題?是SQLServer版本的問題?是沒有分區表的問題?還是程序的問題?

當時時間只有一個星期,一個星期搞不好,專案監管就要我們滾蛋了,於是,有了連續工作48小時的壯舉,有了到處打電話求人的抓雞…

但是,這時候需要的是冷靜,再冷靜一下…SQLServer版本?硬體?目前都不大可能換的。 RAID磁碟陣列,應該不是。那麼到底是什麼,真TM的冷靜不下來。

大家可能體會不到現場那種緊張的氣氛,其實過了這麼久,我自己也都很難再回到那種情境。但可以這麼說,或許我們現在有了各種方法,或者處於局外人我們有更多思考,但是當一個項目壓迫你快到放棄的時候,你那時的想法、考慮在現場環境因素的製約下,都可能出現重大的偏差。有可能讓你快速的思考,也有可能思考停滯。有些同事在這種高壓的環境下,甚至出現了更多的低級錯誤,思維已經完全亂了,效率更低了……36小時沒有合眼,或者只在工地上(下雨天到處都是泥巴,幹了的話到時都是泥灰)瞇兩三個小時,然後繼續幹,連續這麼一週!或者還要繼續!

很多人給了很多想法,但好像有用,好像沒用。等等,為什麼是「好像有用,又好像沒用」?我隱約中,好像抓住了一絲方向,到底是什麼?對了,驗證,我們現在是跑在現場環境下,之前沒有問題,不代表現在的壓力下沒有問題,要在一個大型系統中分析這麼個小功能,影響太大了,我們應該分解它。是的,是“單元測試”,就是單一方法的測試,我們需要驗證每個函數,每個獨立的步驟到底耗時在哪裡?

逐步測試驗證系統瓶頸

修改BulkCopy的參數
首先,我想到的是,修噶BulkCopy的各項參數,BulkCopyTimeoutBatchSize,不斷的測試調整,結果總是在某個範圍波動,實際上並沒有影響。或許會影響一些CPU計數,但是遠遠沒有達到我的期望,寫入的速度還是在5秒1w~2w波動,遠遠達不到要求20秒內要寫20w的記錄。

按擷取裝置儲存
是的,上述結構依每個指標每個值為一筆記錄,是不是太多的浪費?那麼依採集設備 採集時間作為一筆記錄是否可行?問題是,怎麼解決不同採集設備屬性不一樣的問題?這時,一個同事發揮才能了,監控指標 監控值可以依照XML格式儲存。哇,還能這樣?查詢呢,可以用for XML這種形式。

於是有了這種結構:No、MgrObjId、Dtime、XMLData

結果驗證,比上面的稍微好點,但不是太明顯。

資料表分區???
那時候還沒學會這個技能,看了下網路上的文章,好像挺複雜的,時間不多了,不敢嘗試。

停止其他程式
我知道這個肯定是不行的,因為軟體、硬體的架構暫時沒辦法修改。但是我希望驗證是不是這些因素影響的。結果發現,提示確實明顯,但還是沒有達到要求。

難道是SQLServer的瓶頸?
沒轍了,難道這就是SQLServer的瓶頸?上網查了一下相關的資料,可能是IO的瓶頸,尼瑪,還能怎麼辦,要升級伺服器,要更換資料庫了嗎,但是,專案方給嗎?

等等,好像還有個東西,索引,對索引!索引的存在會影響插入、更新

去掉索引

是的,去掉索引之後查詢肯定慢,但我必須先驗證去掉索引是否會加快寫入。如果果斷把MgrObjId和Id兩個欄位的索引去掉。

運行,奇蹟出現了,每次寫入10w筆記錄,在7~9秒內完全可以寫入,這樣就達到了系統的要求。

查詢怎麼解決?

一個表一天要4億多的記錄,這是不可能查詢的,在沒有索引的情況下。怎麼辦! ?我又想到了我們的老方法,物理分錶。是的,原來我們按天分錶,那我們現在就按小時分錶。那麼24個表,每個表只需儲存1800w筆記錄左右。

然後查詢,一個屬性在一個小時或幾個小時的歷史記錄。結果是:慢!慢! !慢! ! !去掉索引的情況下查詢1000多萬的記錄根本是不可想像的。還能怎麼辦?

繼續分錶,我想到了,我們還可以按底層的採集器繼續分錶,因為採集設備在不同的採集器中是不同的,那麼我們查詢歷史曲線時,只有查單個指標的歷史曲線,那麼這樣就可以分散在不同的表格中了。

说干就干,结果,通过按10个采集嵌入式并按24小时分表,每天生成240张表(历史表名类似这样:His_001_2014112615),终于把一天写入4亿多条记录并支持简单的查询这个问题给解决掉了!!!

查询优化

在上述问题解决之后,这个项目的难点已经解决了一半,项目监管也不好意思过来找茬,不知道是出于什么样的战术安排吧。

过了很长一段时间,到现在快年底了,问题又来了,就是要拖死你让你在年底不能验收其他项目。

这次要求是这样的:因为上述是模拟10w个监控指标,而现在实际上线了,却只有5w个左右的设备。那么这个明显是不能达到标书要求的,不能验收。那么怎么办呢?这些聪明的人就想,既然监控指标减半,那么我们把时间也减半,不就达到了吗:就是说按现在5w的设备,那你要10s之内入库存储。我勒个去啊,按你这个逻辑,我们如果只有500个监控指标,岂不是要在0.1秒内入库?你不考虑下那些受监控设备的感想吗?

但是别人要玩你,你能怎么办?接招呗。结果把时间降到10秒之后,问题来了,大家仔细分析上面逻辑可以知道,分表是按采集器分的,现在采集器减少,但是数量增加了,发生什么事情呢,写入可以支持,但是,每张表的记录接近了400w,有些采集设备监控指标多的,要接近600w,怎么破?

于是技术相关人员开会讨论相关的举措。

在不加索引的情况下怎么优化查询?

有同事提出了,where子句的顺序,会影响查询的结果,因为按你刷选之后的结果再处理,可以先刷选出一部分数据,然后继续进行下一个条件的过滤。听起来好像很有道理,但是SQLServer查询分析器不会自动优化吗?原谅我是个小白,我也是感觉而已,感觉应该跟VS的编译器一样,应该会自动优化吧。

具体怎样,还是要用事实来说话:

结果同事修改了客户端之后,测试反馈,有较大的改善。我查看了代码:

难道真的有这么大的影响?等等,是不是忘记清空缓存,造成了假象?
于是让同事执行下述语句以便得出更多的信息:

--优化之前DBCC FREEPROCCACHEDBCC DROPCLEANBUFFERSSET STATISTICS IO ONselect Dtime,Value from dbo.his20140825 WHERE  Dtime>=&#39;&#39; AND Dtime<=&#39;&#39; AND MgrObjId=&#39;&#39; AND Id=&#39;&#39;SET STATISTICS IO OFF--优化之后DBCC FREEPROCCACHEDBCC DROPCLEANBUFFERSSET STATISTICS IO ONselect Dtime,Value from dbo.his20140825 WHERE MgrObjId=&#39;&#39; AND Id=&#39;&#39; AND Dtime>=&#39;&#39; AND Dtime<=&#39;&#39;SET STATISTICS IO OFF

结果如下:

优化之前反而更好了?

仔细查看IO数据,发现,预读是一样的,就是说我们要查询的数据记录都是一致的,物理读、表扫描也是一直的。而逻辑读取稍有区别,应该是缓存命中数导致的。也就是说,在不建立索引的情况下,where子句的条件顺序,对查询结果优化作用不明显

那么,就只能通过索引的办法了。

建立索引的尝试

建立索引不是简单的事情,是需要了解一些基本的知识的,在这个过程中,我走了不少弯路,最终才把索引建立起来。

下面的实验基于以下记录总数做的验证:

按单个字段建立索引
这个想法,主要是受我建立数据结构影响的,我内存中的数据结构为:Dictionary<mgrobjid>></mgrobjid>。我以为先建立MgrObjId的索引,再建立Id的索引,SQLServer查询时,就会更快。

先按MgrObjId建立索引,索引大小为550M,耗时5分25秒。结果,如上图的预估计划一样,根本没有起作用,反而更慢了。

按多个条件建立索引
OK,既然上面的不行,那么我们按多个条件建立索引又如何?CREATE NONCLUSTERED INDEX Idx_His20141008 ON dbo.his20141008(MgrObjId,Id,Dtime)

结果,查询速度确实提高了一倍:

等等,难道这就是索引的好处?花费7分25秒,用1.1G的空间换取来的就是这些?肯定是有什么地方不对了,于是开始翻查资料,查看一些相关书籍,最终,有了较大的进展。

正确的建立索引

首先,我们需要明白几个索引的要点:

  • 索引之後,依索引欄位重複最少的來排序,會達到最優的效果。以我們的表來說,如果建立了No的聚集索引,把No放在where子句的第一位是最佳的,其次是Id,然後是MgrObjId,最後是時間,時間索引如果表是一個小時的,最好不要用
  • where子句的順序決定了查詢分析器是否使用索引來查詢。例如建立了MgrObjId和Id的索引,那麼where MgrObjId='' and Id='' and Dtime=''就會採用索引查找,而where Dtime='' and MgrObjId=' ' and Id=''則不一定會採用索引查找。
  • 把非索引列的結果欄位放在包含列中。因為我們條件是MgrObjId和Id以及Dtime,因此返回結果中只需包含Dtime和Value即可,因此把Dtime和Value放在包含列中,返回的索引結果就有這個值,不用再查物理表,可以達到最優的速度。

跟上述幾點原則,我們建立以下的索引:CREATE NONCLUSTERED INDEX Idx_His20141008 ON dbo.his20141008(MgrObjId,Id) INCLUDE(Value,Dtime)

耗費時間為:6分多鐘,索引大小為903M。

我們看看預估計畫:

可以看到,這裡完全使用了索引,沒有額外的消耗。而實際執行的結果,1秒都不到,竟然不用一秒就在1100w的記錄中把結果篩選了出來! !帥呆了! !

怎麼應用索引?

既然寫入完成了、讀取完成了,怎麼結合呢?我們可以把一個小時之前的資料建立索引,目前一個小時的資料就不建立索引。也就是,不要再建立表格的時候建立索引! !

還能怎麼最佳化

可以嘗試讀寫分離,寫兩個函式庫,一個是即時函式庫,一個是唯讀函式庫。一個小時內的數據查詢實時庫,一個小時之前的數據查詢只讀庫;只讀庫定時存儲,然後建立索引;超過一個星期的數據,進行分析處理再存儲。這樣,無論查詢什麼時間段的數據,都能夠正確處理了——一個小時之內的查詢實時庫,一個小時到一個星期內的查詢只讀庫,一個星期之前的查詢報表庫。

如果不需要實體分錶,則在唯讀函式庫中,定時重建索引即可。

總結

如何在SQLServer中處理億萬層級的資料(歷史資料),可以按以下方面進行:

  • 去掉表的所​​有索引
  • 都用SqlBulkCopy進行插入
  • 分錶或分區,減少每個表的資料總量
  • 在某個表完全寫完之後再建立索引
  • 正確的指定索引欄位
  • 把需要用到的欄位放到包含索引中(在傳回的索引中就包含了一切)
  • 查詢的時候只傳回所需的欄位                                            # 

以上是學習在SQLServer中處理千萬單位記錄的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:learnku。如有侵權,請聯絡admin@php.cn刪除
SQL和數據庫:完美的合作夥伴關係SQL和數據庫:完美的合作夥伴關係Apr 25, 2025 am 12:04 AM

SQL與數據庫的關係是緊密結合的,SQL是管理和操作數據庫的工具。 1.SQL是一種聲明式語言,用於數據定義、操作、查詢和控制。 2.數據庫引擎解析SQL語句並執行查詢計劃。 3.基本用法包括創建表、插入和查詢數據。 4.高級用法涉及復雜查詢和子查詢。 5.常見錯誤包括語法、邏輯和性能問題,可通過語法檢查和EXPLAIN命令調試。 6.優化技巧包括使用索引、避免全表掃描和優化查詢。

SQL與MySQL:澄清兩者之間的關係SQL與MySQL:澄清兩者之間的關係Apr 24, 2025 am 12:02 AM

SQL是一種用於管理關係數據庫的標準語言,而MySQL是一個使用SQL的數據庫管理系統。 SQL定義了與數據庫交互的方式,包括CRUD操作,而MySQL實現了SQL標準並提供了額外的功能,如存儲過程和触發器。

SQL的重要性:數字時代的數據管理SQL的重要性:數字時代的數據管理Apr 23, 2025 am 12:01 AM

SQL在數據管理中的作用是通過查詢、插入、更新和刪除操作來高效處理和分析數據。 1.SQL是一種聲明式語言,允許用戶以結構化方式與數據庫對話。 2.使用示例包括基本的SELECT查詢和高級的JOIN操作。 3.常見錯誤如忘記WHERE子句或誤用JOIN,可通過EXPLAIN命令調試。 4.性能優化涉及使用索引和遵循最佳實踐如代碼可讀性和可維護性。

SQL入門:基本概念和技能SQL入門:基本概念和技能Apr 22, 2025 am 12:01 AM

SQL是一種用於管理和操作關係數據庫的語言。 1.創建表:使用CREATETABLE語句,如CREATETABLEusers(idINTPRIMARYKEY,nameVARCHAR(100),emailVARCHAR(100));2.插入、更新、刪除數據:使用INSERTINTO、UPDATE、DELETE語句,如INSERTINTOusers(id,name,email)VALUES(1,'JohnDoe','john@example.com');3.查詢數據:使用SELECT語句,如SELEC

SQL:語言,MySQL:數據庫管理系統SQL:語言,MySQL:數據庫管理系統Apr 21, 2025 am 12:05 AM

SQL和MySQL的關係是:SQL是用於管理和操作數據庫的語言,而MySQL是支持SQL的數據庫管理系統。 1.SQL允許進行數據的CRUD操作和高級查詢。 2.MySQL提供索引、事務和鎖機制來提升性能和安全性。 3.優化MySQL性能需關注查詢優化、數據庫設計和監控維護。

SQL的作用:管理和操縱數據SQL的作用:管理和操縱數據Apr 20, 2025 am 12:02 AM

SQL用於數據庫管理和數據操作,核心功能包括CRUD操作、複雜查詢和優化策略。 1)CRUD操作:使用INSERTINTO創建數據,SELECT讀取數據,UPDATE更新數據,DELETE刪除數據。 2)複雜查詢:通過GROUPBY和HAVING子句處理複雜數據。 3)優化策略:使用索引、避免全表掃描、優化JOIN操作和分頁查詢來提升性能。

SQL:對數據管理的初學者友好方法?SQL:對數據管理的初學者友好方法?Apr 19, 2025 am 12:12 AM

SQL適合初學者,因為它語法簡單,功能強大,廣泛應用於數據庫系統。 1.SQL用於管理關係數據庫,通過表格組織數據。 2.基本操作包括創建、插入、查詢、更新和刪除數據。 3.高級用法如JOIN、子查詢和窗口函數增強數據分析能力。 4.常見錯誤包括語法、邏輯和性能問題,可通過檢查和優化解決。 5.性能優化建議包括使用索引、避免SELECT*、使用EXPLAIN分析查詢、規範化數據庫和提高代碼可讀性。

SQL在行動中:現實世界中的示例和用例SQL在行動中:現實世界中的示例和用例Apr 18, 2025 am 12:13 AM

SQL在實際應用中主要用於數據查詢與分析、數據整合與報告、數據清洗與預處理、高級用法與優化以及處理複雜查詢和避免常見錯誤。 1)數據查詢與分析可用於找出銷售量最高的產品;2)數據整合與報告通過JOIN操作生成客戶購買報告;3)數據清洗與預處理可刪除異常年齡記錄;4)高級用法與優化包括使用窗口函數和創建索引;5)處理複雜查詢可使用CTE和JOIN,避免常見錯誤如SQL注入。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器