數據庫調優過程(一):SqlServer批量復制(bcp)[C#SqlBulkCopy]性能極低問題


  • 背景

  最近一段給xx做項目,這邊最頭疼的事情就是數據庫入庫瓶頸問題。 

  • 環境

  服務器環境:虛擬機,分配32CPU,磁盤1.4T,4T,5T,6T幾台服務器不等同(轉速都是7200r),內存64G。

  • 排查步驟

  排查一:數據庫恢復模式為簡單模式,數據庫和tempdb的初始大小。數據庫文件初始化大小100G,日志文件初始化大小50G,兩個文件都是自動增長(按10%);tempdb初始化大小10G*4個文件,日志5G*4個文件,兩個文件都是自動增長(按10%),分布在兩個磁盤中(但看了這篇文章后,有點傻眼了。);

排查二:設置數據庫占用最大內存為30G;

排查二:數據庫表刪掉所有索引,除了PK(OID bigint,Time datetime)分區使用了Time字段(看了這篇文章,為后邊擔憂);

排查三:系統windows server 2008(Vista內核),升級為windows server 2008 R2 SP1(WIN7內核);

排查四:批量入庫一次批量入庫的次數,目前還在調整中,把BatchSize設置為一個合適的值,是50W,還是200W呢?(BCP原理篇推薦參數配置設置多大合適?

測試結果:

-- 300w batch insert two tables,batch size:1w ,with (first table with 5ix+pk,second table with 1ix+pk)
--server:ip\network 8 minutes

-- 300w batch insert two tables,batch size:300w,with (first table with 5ix+pk,second table with 1ix+pk)
--server:ip\network 8 minutes

-- 300w batch insert two tables,batch size:1000,with (first table with 0ix+pk,second table with 0ix+pk)
--server:local\network 8 minutes

-- 300w batch insert two tables,batch size:5000,with (first table with 0ix+pk,second table with 0ix+pk)
--server:local\network 4.5 minutes

-- 300w batch insert two tables,batch size:1w,with (first table with 0ix+pk,second table with 0ix+pk)
--server:local\network 4 minutes


-- 300w batch insert two tables,batch size:5w,with (first table with 0ix+pk,second table with 0ix+pk)
--server:local\network 5 minutes


-- 300w batch insert two tables,batch size:10w,with (first table with 0ix+pk,second table with 0ix+pk)
--server:local\network 4.5 minutes


-- 300w batch insert two tables,batch size:50w,with (first table with 0ix+pk,second table with 0ix+pk)
--server:local\network 5 minutes

測試2:

records 500000
batchsize 5000
insert two tables(first table with 0ix,1pk)
use times:first table use:29s,second table use:19s

records 500000
batchsize 10000
insert two tables(first table with 0ix,1pk)
use times:first table use:22s,second table use:14s

records 500000
batchsize 50000
insert two tables(first table with 0ix,1pk)
use times:first table use: 30s,second table use:18s

排查五:數據庫連接字符串把172.21.xxx.xxx\work,修改為(local)\work或者.\work,是否可以采用共享內存的方式來建立連接呢?目前還未測試。(實戰篇微軟文檔篇)

連接字符串參數:

Data Source

- 或 -

Server

- 或 -

Address

- 或 -

Addr

- 或 -

Network Address

默認值:

N/A

要連接的 SQL Server 實例的名稱或網絡地址。可以在服務器名稱之后指定端口號:

server=tcp:servername, portnumber

指定本地實例時,始終使用 (local)。若要強制使用某個協議,請添加下列前綴之一:

np:(local), tcp:(local), lpc:(local)

連接字符串參數:

Network Library

- 或 -

Net

默認值:

'dbmssocn'

用於建立與 SQL Server 實例的連接的網絡庫。支持的值包括 dbnmpntw(命名管道)、dbmsrpcn(多協議)、dbmsadsn (Apple Talk)、dbmsgnet (VIA)、dbmslpcn(共享內存)及 dbmsspxn (IPX/SPX) 和 dbmssocn (TCP/IP)。

相應的網絡 DLL 必須安裝在要連接的系統上。如果不指定網絡而使用一個本地服務器(比如“.”或“(local)”),則使用共享內存。

排查六:SqlBulkCopy參數SqlBulkCopyOptions設置

1. 有標識列的表
  1. 1 SqlBulkCopyOptions.KeepIdentity 必須設置!否則會出現復制過去的數據產生標識列發現變化的情況!
  1.2 如果原表的標識列即為主鍵, 那按1.1 的設置已足夠。 如果原表無主鍵, 那在復制之前必須先清空原表(truncate table), 否則會出現多個相同的標識值的列!
2. 為NULL值的列
  2.1 SqlBulkCopyOptions.KeepNulls 必須設置!否則會出現源數據的字段為NULL時, 復制過去卻成了默認值!

其它幾個選項的說明與分析:
  Default 對所有選項使用默認值。
  KeepIdentity 保留源標識值。如果未指定,則由目標分配標識值。
  CheckConstraints 請在插入數據的同時檢查約束。默認情況下,不檢查約束。
  TableLock 在批量復制操作期間獲取批量更新鎖。如果未指定,則使用行鎖。
  KeepNulls 保留目標表中的空值,而不管默認值的設置如何。如果未指定,則空值將由默認值替換(如果適用)。
  FireTriggers 指定后,會導致服務器為插入到數據庫中的行激發插入觸發器。 默認情況下, 是不激發觸發器的……
  UseInternalTransaction 如果已指定,則每一批批量復制操作將在事務中發生。 在一個事務中執行,要么都成功,要么都不成功。

Default 就沒有什么好說的了, 不要
KeepIdentity 和 KeepNulls 上面已有了, 不再分析。
CheckConstraints 不需要, 因為是現成的數據, 既然已在DB中, 必然是通過了約束檢查的。
TableLock 不需要, 因為復制時兩個庫都需要處於單連接狀態, 不可能有干擾。
FireTriggers 一般就不需要了吧, 畢竟只是復制數據, 而且是現成的數據……
UseInternalTransaction 關系也不大, 反正復制失敗會記錄到自定義的日志, 失敗了也知道, 重來一次就可以了。

 排查七、表是否有trigger,check等。

參考資料:http://stackoverflow.com/questions/15526797/sqlbulkcopy-performance

Prerequisites for Minimal Logging in Bulk Import:https://msdn.microsoft.com/en-us/library/ms190422(v=sql.105).aspx

Optimizing Bulk Import Performance:https://msdn.microsoft.com/en-us/library/ms190421(v=sql.105).aspx

 

  • 別人給的建議

ETL來處理:

  針對這個解決方案,搜索了后才知道微軟的SSIS中是支持ETL的(實戰1實戰2篇,微軟文檔篇)。具體需要測試才知道結果。

 內存處理:

  就是把未能處理的數據放到內存中,使用Redis或者memcached來存儲,之后把這樣的數據源排隊性的存儲到sqlsever 2008 R2數據庫中,該方案可行性還需要測試,到底需要多大的設備,一個上邊同樣配置的虛擬機能存儲多少條記錄會內存滿負載,這是該方案是否成立的根本問題,問題是我們需要的是數據量在幾百億量級的數據,這樣的情況需要測試才會有結論。

  另外,看到SqlServer2014(SQL 2014新功能介紹系列1 – 內存中 OLTP (In-Memory OLTP))也做了比較大的調整,基本上支持內存存儲,可以異步快速存儲到內存中,該方案以目前設備來說,恐怕行不通。

  其他,后來搜索過程中學習到了怎么實現一個復制的,復制的場景的應用模式(實戰篇)。

用Oracle來替換SqlServer:

  該方案我也早想去這么去做,回去就給公司建議,不過公司一定會PASS的。。。

 

 

 

 

參考資料:

DBA博客:http://www.cnblogs.com/CareySon/archive/2012/05/08/2489748.html

DBA問題查找經驗總結:http://blog.csdn.net/yynetsdk/article/details/6749529

SqlBulkCopy 實現原汁原味復制的注意事項:http://blog.csdn.net/yenange/article/details/35837247


免責聲明!

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



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