亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 數據庫 > SQL Server > 正文

SQL批量插入數據幾種方案的性能詳細對比

2024-08-31 00:58:54
字體:
來源:轉載
供稿:網友
公司技術背景:數據庫訪問類(xxx.DataBase.Dll)調用存儲過程實現數據庫的訪問。

技術方案一:

壓縮時間下程序員寫出的第一個版本,僅僅為了完成任務,沒有從程序上做任何優化,實現方式是利用數據庫訪問類調用存儲過程,利用循環逐條插入。很明顯,這種方式效率并不高,于是有了前面的兩位同事討論效率低的問題。

技術方案二:

由于是考慮到大數據量的批量插入,于是我想到了ADO.NET2.0的一個新的特性:SqlBulkCopy。有關這個的性能,很早之前我是親自做過性能測試的,效率非常高。這也是我向公司同事推薦的技術方案。

技術方案三:

利用SQLServer2008的新特性--表值參數(Table-Valued Parameter)。表值參數是SQLServer2008才有的一個新特性,使用這個新特性,我們可以把一個表類型作為參數傳遞到函數或存儲過程里。不過,它也有一個特點:表值參數在插入數目少于 1000 的行時具有很好的執行性能。

技術方案四:

對于單列字段,可以把要插入的數據進行字符串拼接,最后再在存儲過程中拆分成數組,然后逐條插入。查了一下存儲過程中參數的字符串的最大長度,然后除以字段的長度,算出一個值,很明顯是可以滿足要求的,只是這種方式跟第一種方式比起來,似乎沒什么提高,因為原理都是一樣的。

技術方案五:

考慮異步創建、消息隊列等等。這種方案無論從設計上還是開發上,難度都是有的。

技術方案一肯定是要被否掉的了,剩下的就是在技術方案二跟技術方案三之間做一個抉擇,鑒于公司目前的情況,技術方案四跟技術方案五就先不考慮了。

接下來,為了讓大家對表值參數的創建跟調用有更感性的認識,我將寫的更詳細些,文章可能也會稍長些,不關注細節的朋友們可以選擇跳躍式的閱讀方式。

再說一下測試方案吧,測試總共分三組,一組是插入數量小于1000的,另外兩組是插入數據量大于1000的(這里我們分別取10000跟1000000),每組測試又分10次,取平均值。怎么做都明白了,Let's go!

1.創建表。

為了簡單,表中只有一個字段,如下圖所示:

2.創建表值參數類型

我們打開查詢分析器,然后在查詢分析器中執行下列代碼:

Create Type PassportTableType as Table(PassportKey nvarchar(50)
)

執行成功以后,我們打開企業管理器,按順序依次展開下列節點--數據庫、展開可編程性、類型、用戶自定義表類型,就可以看到我們創建好的表值類型了如下圖所示:

SQL批量插入數據幾種方案的性能詳細對比

說明我們創建表值類型成功了。

3.編寫存儲過程

存儲過程的代碼為:

復制代碼 代碼如下:


USE [TestInsert]
GO
/****** Object: StoredProcedure [dbo].[CreatePassportWithTVP] Script Date: 03/02/2010 00:14:45 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:    <Kevin>
-- Create date: <2010-3-1>
-- Description:    <創建通行證>
-- =============================================
Create PROCEDURE [dbo].[CreatePassportWithTVP]
@TVP PassportTableType readonly
AS
BEGIN
SET NOCOUNT ON;
Insert into Passport(PassportKey) select PassportKey from @TVP
END


可能在查詢分析器中,智能提示會提示表值類型有問題,會出現紅色下劃線(見下圖),不用理會,繼續運行我們的代碼,完成存儲過程的創建

SQL批量插入數據幾種方案的性能詳細對比

 
4.編寫代碼調用存儲過程。

三種數據庫的插入方式代碼如下,由于時間比較緊,代碼可能不那么易讀,特別代碼我加了些注釋。

復制代碼 代碼如下:


using System;
using System.Diagnostics;
using System.Data;
using System.Data.SqlClient;
using com.DataAccess;
namespace ConsoleAppInsertTest
{
class Program
{
static string connectionString = SqlHelper.ConnectionStringLocalTransaction; //數據庫連接字符串
static int count = 1000000; //插入的條數
static void Main(string[] args)
{
//long commonInsertRunTime = CommonInsert();
//Console.WriteLine(string.Format("普通方式插入{1}條數據所用的時間是{0}毫秒", commonInsertRunTime, count));
long sqlBulkCopyInsertRunTime = SqlBulkCopyInsert();
Console.WriteLine(string.Format("使用SqlBulkCopy插入{1}條數據所用的時間是{0}毫秒", sqlBulkCopyInsertRunTime, count));
long TVPInsertRunTime = TVPInsert();
Console.WriteLine(string.Format("使用表值方式(TVP)插入{1}條數據所用的時間是{0}毫秒", TVPInsertRunTime, count));
}
/// <summary>
/// 普通調用存儲過程插入數據
/// </summary>
/// <returns></returns>
private static long CommonInsert()
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
string passportKey;
for (int i = 0; i < count; i++)
{
passportKey = Guid.NewGuid().ToString();
SqlParameter[] sqlParameter = { new SqlParameter("@passport", passportKey) };
SqlHelper.ExecuteNonQuery(connectionString, CommandType.StoredProcedure, "CreatePassport", sqlParameter);
}
stopwatch.Stop();
return stopwatch.ElapsedMilliseconds;
}
/// <summary>
/// 使用SqlBulkCopy方式插入數據
/// </summary>
/// <param></param>
/// <returns></returns>
private static long SqlBulkCopyInsert()
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
DataTable dataTable = GetTableSchema();
string passportKey;
for (int i = 0; i < count; i++)
{
passportKey = Guid.NewGuid().ToString();
DataRow dataRow = dataTable.NewRow();
dataRow[0] = passportKey;
dataTable.Rows.Add(dataRow);
}
SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(connectionString);
sqlBulkCopy.DestinationTableName = "Passport";
sqlBulkCopy.BatchSize = dataTable.Rows.Count;
SqlConnection sqlConnection = new SqlConnection(connectionString);
sqlConnection.Open();
if (dataTable!=null && dataTable.Rows.Count!=0)
{
sqlBulkCopy.WriteToServer(dataTable);
}
sqlBulkCopy.Close();
sqlConnection.Close();
stopwatch.Stop();
return stopwatch.ElapsedMilliseconds;
}
private static long TVPInsert()
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
DataTable dataTable = GetTableSchema();
string passportKey;
for (int i = 0; i < count; i++)
{
passportKey = Guid.NewGuid().ToString();
DataRow dataRow = dataTable.NewRow();
dataRow[0] = passportKey;
dataTable.Rows.Add(dataRow);
}
SqlParameter[] sqlParameter = { new SqlParameter("@TVP", dataTable) };
SqlHelper.ExecuteNonQuery(connectionString, CommandType.StoredProcedure, "CreatePassportWithTVP", sqlParameter);
stopwatch.Stop();
return stopwatch.ElapsedMilliseconds;
}
private static DataTable GetTableSchema()
{
DataTable dataTable = new DataTable();
dataTable.Columns.AddRange(new DataColumn[] { new DataColumn("PassportKey") });
return dataTable;
}
}
}


比較神秘的代碼其實就下面這兩行,該代碼是將一個dataTable做為參數傳給了我們的存儲過程。簡單吧。

SqlParameter[] sqlParameter = { new SqlParameter("@TVP", dataTable) };
SqlHelper.ExecuteNonQuery(connectionString, CommandType.StoredProcedure, "CreatePassportWithTVP", sqlParameter);5.測試并記錄測試結果第一組測試,插入記錄數1000

SQL批量插入數據幾種方案的性能詳細對比


第二組測試,插入記錄數10000

SQL批量插入數據幾種方案的性能詳細對比


第三組測試,插入記錄數1000000

SQL批量插入數據幾種方案的性能詳細對比


通過以上測試方案,不難發現,技術方案二的優勢還是蠻高的。無論是從通用性還是從性能上考慮,都應該是
優先被選擇的,還有一點,它的技術復雜度要比技術方案三要簡單一些,

設想我們把所有表都創建一遍表值類型,工作量還是有的。因此,我依然堅持我開始時的決定,
向公司推薦使用第二種技術方案。

寫到此,本文就算完了,但是對新技術的鉆研仍然還在不斷繼續。要做的東西還是挺多的。

為了方便大家學習和交流,代碼文件已經打包并上傳了,歡迎共同學習探討。
代碼下載
作者:深山老林
出處:

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲精品国产精品乱码不99按摩| 日韩黄在线观看| 国产成人综合av| 久久资源免费视频| 国产又爽又黄的激情精品视频| 深夜精品寂寞黄网站在线观看| 欧美高清不卡在线| 亚洲午夜精品久久久久久性色| 黑人巨大精品欧美一区免费视频| 国产成人综合一区二区三区| 亚洲电影免费观看高清完整版| 精品久久久视频| 亚洲欧美日韩区| 久99九色视频在线观看| 亚洲欧美综合另类中字| 欧美精品午夜视频| 日本在线精品视频| 国产亚洲精品久久久优势| 国产精品视频自在线| 韩日欧美一区二区| 欧美在线观看一区二区三区| 这里只有精品在线播放| 色爱精品视频一区| 国产成人精品国内自产拍免费看| 国自产精品手机在线观看视频| 色噜噜国产精品视频一区二区| 国内精品久久久久久| 国产美女久久精品香蕉69| 97香蕉久久超级碰碰高清版| 国产欧美日韩精品丝袜高跟鞋| 奇门遁甲1982国语版免费观看高清| 国模吧一区二区三区| 午夜精品理论片| 国产午夜精品免费一区二区三区| 日韩精品极品在线观看| 欧美性猛交xxxx富婆弯腰| 亚洲三级免费看| 欧美日韩中文在线观看| 精品视频一区在线视频| 亚洲视频在线播放| 亚洲国产精品中文| 国产精品91久久| 国产中文欧美精品| 成人福利视频在线观看| 国内精品小视频| 日韩亚洲国产中文字幕| 亚洲国产精品国自产拍av秋霞| 亚洲另类欧美自拍| 亚洲精品v欧美精品v日韩精品| 91超碰中文字幕久久精品| 92看片淫黄大片欧美看国产片| 国产va免费精品高清在线观看| 日韩中文字幕视频在线观看| 亚州欧美日韩中文视频| 国产做受69高潮| 97视频在线免费观看| 亚洲免费av网址| 精品亚洲一区二区三区在线播放| 国产一区二区欧美日韩| 国产精品老女人视频| 日本最新高清不卡中文字幕| 国产在线观看精品| 国产欧美亚洲视频| 亚洲高清在线观看| 81精品国产乱码久久久久久| 欧美最猛性xxxxx免费| 亚洲精品自在久久| 91国内在线视频| www.99久久热国产日韩欧美.com| 欧美在线影院在线视频| 亚洲高清一二三区| 日韩精品免费综合视频在线播放| 91极品女神在线| 欧美午夜丰满在线18影院| 国产精品91一区| 国产激情久久久久| 在线观看成人黄色| 国产亚洲精品美女久久久| 欧美日韩国产麻豆| 久久久久久久久爱| 国产69久久精品成人| 国产盗摄xxxx视频xxx69| 自拍偷拍亚洲欧美| yellow中文字幕久久| 日韩av片免费在线观看| 最新亚洲国产精品| 日产精品久久久一区二区福利| 亚洲精品资源美女情侣酒店| 欧美日本啪啪无遮挡网站| 91亚洲国产精品| 国产精品视频区| 欧美亚洲在线播放| 亚洲影院色无极综合| 亚洲一区二区中文字幕| 日韩福利视频在线观看| 国产精品久久久久77777| 日韩美女在线看| 欧美激情国产日韩精品一区18| 欧美高清自拍一区| 欧美亚洲国产成人精品| 亚洲国产婷婷香蕉久久久久久| 日本三级久久久| 国产欧美日韩中文字幕| 国产一区二区三区精品久久久| 欧美一级免费视频| 国产日韩精品在线观看| 97视频在线观看网址| 国产精品久久久久久中文字| 98精品国产高清在线xxxx天堂| 在线观看日韩视频| 久久久在线视频| 欧美www在线| 久久综合国产精品台湾中文娱乐网| 欧美黑人性生活视频| 精品国产一区二区三区久久| 国产精品aaa| 欧美成人午夜剧场免费观看| 国产高清在线不卡| 亚洲人成77777在线观看网| 日韩极品精品视频免费观看| 奇门遁甲1982国语版免费观看高清| 国产精品久久久一区| 欧美亚洲免费电影| 久久精品一区中文字幕| 中文字幕少妇一区二区三区| 成人妇女免费播放久久久| 成人性生交xxxxx网站| 日韩成人高清在线| 亚洲国产精久久久久久| 亚洲国产精品久久久久秋霞不卡| 亚洲精品丝袜日韩| 日韩中文综合网| 日韩中文在线中文网在线观看| 国产成人拍精品视频午夜网站| 91国内在线视频| 97人洗澡人人免费公开视频碰碰碰| 一区二区三区视频在线| 91免费的视频在线播放| 在线观看欧美日韩国产| 久久成人精品视频| 最近日韩中文字幕中文| 日韩av在线最新| 91精品综合久久久久久五月天| 欧美日韩一区二区三区在线免费观看| 亚洲美女福利视频网站| 亚洲人成在线免费观看| 亚洲欧美日韩国产中文专区| 色偷偷9999www| 91av在线不卡| 欧美中文字幕精品| 亚洲精品视频久久| 久久国产精品久久久久久久久久| 久久久久久国产精品久久| 在线精品国产成人综合| 亚洲成人网久久久| 欧美日韩在线观看视频小说| 日韩女优人人人人射在线视频| 亚洲欧美日韩中文视频| 久久影视三级福利片| 欧美成人免费网| 国产专区欧美专区| 久热99视频在线观看| 亚洲精品一区久久久久久| 亚洲精品网址在线观看|