最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SQL批量插入數(shù)據(jù)幾種方案的性能詳細對比

 更新時間:2010年03月13日 13:35:34   作者:  
昨天下午快下班的時候,無意中聽到公司兩位同事在探討批量向數(shù)據(jù)庫插入數(shù)據(jù)的性能優(yōu)化問題,頓時來了興趣,把自己的想法向兩位同事說了一下,于是有了本文。
公司技術(shù)背景:數(shù)據(jù)庫訪問類(xxx.DataBase.Dll)調(diào)用存儲過程實現(xiàn)數(shù)據(jù)庫的訪問。

技術(shù)方案一:

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

技術(shù)方案二:

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

技術(shù)方案三:

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

技術(shù)方案四:

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

技術(shù)方案五:

考慮異步創(chuàng)建、消息隊列等等。這種方案無論從設(shè)計上還是開發(fā)上,難度都是有的。

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

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

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

1.創(chuàng)建表。

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

2.創(chuàng)建表值參數(shù)類型

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

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

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

說明我們創(chuàng)建表值類型成功了。

3.編寫存儲過程

存儲過程的代碼為:

復(fù)制代碼 代碼如下:

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:    <創(chuàng)建通行證>
-- =============================================
Create PROCEDURE [dbo].[CreatePassportWithTVP]
@TVP PassportTableType readonly
AS
BEGIN
SET NOCOUNT ON;
Insert into Passport(PassportKey) select PassportKey from @TVP
END

可能在查詢分析器中,智能提示會提示表值類型有問題,會出現(xiàn)紅色下劃線(見下圖),不用理會,繼續(xù)運行我們的代碼,完成存儲過程的創(chuàng)建
 
4.編寫代碼調(diào)用存儲過程。

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

using System;
using System.Diagnostics;
using System.Data;
using System.Data.SqlClient;
using com.DataAccess;
namespace ConsoleAppInsertTest
{
class Program
{
static string connectionString = SqlHelper.ConnectionStringLocalTransaction; //數(shù)據(jù)庫連接字符串
static int count = 1000000; //插入的條數(shù)
static void Main(string[] args)
{
//long commonInsertRunTime = CommonInsert();
//Console.WriteLine(string.Format("普通方式插入{1}條數(shù)據(jù)所用的時間是{0}毫秒", commonInsertRunTime, count));
long sqlBulkCopyInsertRunTime = SqlBulkCopyInsert();
Console.WriteLine(string.Format("使用SqlBulkCopy插入{1}條數(shù)據(jù)所用的時間是{0}毫秒", sqlBulkCopyInsertRunTime, count));
long TVPInsertRunTime = TVPInsert();
Console.WriteLine(string.Format("使用表值方式(TVP)插入{1}條數(shù)據(jù)所用的時間是{0}毫秒", TVPInsertRunTime, count));
}
/// <summary>
/// 普通調(diào)用存儲過程插入數(shù)據(jù)
/// </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方式插入數(shù)據(jù)
/// </summary>
/// <param name="dataTable"></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做為參數(shù)傳給了我們的存儲過程。簡單吧。

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

第二組測試,插入記錄數(shù)10000

第三組測試,插入記錄數(shù)1000000

通過以上測試方案,不難發(fā)現(xiàn),技術(shù)方案二的優(yōu)勢還是蠻高的。無論是從通用性還是從性能上考慮,都應(yīng)該是
優(yōu)先被選擇的,還有一點,它的技術(shù)復(fù)雜度要比技術(shù)方案三要簡單一些,

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

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

為了方便大家學(xué)習(xí)和交流,代碼文件已經(jīng)打包并上傳了,歡迎共同學(xué)習(xí)探討。
代碼下載
作者:深山老林
出處:http://wlb.cnblogs.com/

相關(guān)文章

  • MSSQL 事務(wù)說明

    MSSQL 事務(wù)說明

    事務(wù)是一個不可分割的工作邏輯單元,在數(shù)據(jù)庫系統(tǒng)上執(zhí)行并發(fā)操作時事務(wù)是做為最小的控制單元來使用的。
    2010-06-06
  • SQLServer或Oracle卸載不完全導(dǎo)致安裝失敗的解決辦法

    SQLServer或Oracle卸載不完全導(dǎo)致安裝失敗的解決辦法

    這篇文章主要介紹了SQLServer或Oracle卸載不完全導(dǎo)致安裝失敗的解決辦法,本文歸根結(jié)底的辦法就是利用cmd命令行將未卸載完全的插件或程序進行完美卸載,文中介紹的非常詳細,需要的朋友可以參考下
    2024-05-05
  • 深入理解SQL盲注

    深入理解SQL盲注

    本文主要介紹了深入理解SQL盲注,主要介紹了布爾盲注和時間盲注,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-01-01
  • sql server中datetime字段去除時間的語句

    sql server中datetime字段去除時間的語句

    sql server中datetime字段去除時間的語句...
    2007-08-08
  • SQL Server中實現(xiàn)數(shù)據(jù)庫的自定義視圖

    SQL Server中實現(xiàn)數(shù)據(jù)庫的自定義視圖

    在SQL Server的數(shù)據(jù)處理和分析中,視圖(View)是一種虛擬的表,其內(nèi)容由SQL查詢定義,自定義視圖允許用戶根據(jù)需要創(chuàng)建個性化的數(shù)據(jù)展示,本文將詳細介紹如何在SQL Server中實現(xiàn)數(shù)據(jù)庫的自定義視圖,需要的朋友可以參考下
    2024-07-07
  • Sql Server數(shù)據(jù)遷移的實現(xiàn)場景及示例

    Sql Server數(shù)據(jù)遷移的實現(xiàn)場景及示例

    在 SQL Server 中,數(shù)據(jù)遷移是常見的場景之一,本文主要介紹了Sql Server數(shù)據(jù)遷移的實現(xiàn)場景及示例,具有一定的參考價值,感興趣的可以了解一下
    2024-04-04
  • SQL Server 中查看SQL句子執(zhí)行所用的時間

    SQL Server 中查看SQL句子執(zhí)行所用的時間

    在MSSQL Server中通過查看SQL語句執(zhí)行所用的時間,來衡量SQL語句的性能。
    2009-07-07
  • SQL Server中分區(qū)表的用法

    SQL Server中分區(qū)表的用法

    本文詳細講解了SQL Server中分區(qū)表的用法,文中通過示例代碼介紹的非常詳細。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-05-05
  • SQLSERVER如何查看索引缺失及DMV使用介紹

    SQLSERVER如何查看索引缺失及DMV使用介紹

    當(dāng)我們發(fā)現(xiàn)數(shù)據(jù)庫查詢性能很慢的時候,大家都會想到加索引來優(yōu)化數(shù)據(jù)庫查詢性能,在短時間之內(nèi)找到一個優(yōu)化的索引組合對人腦來講,不是一件簡單的事啊,所以有了本文的出現(xiàn),感興趣的你可不要錯過了哈
    2013-02-02
  • SQL?Server安裝后本地服務(wù)器連接失敗的解決方法(僅供參考)

    SQL?Server安裝后本地服務(wù)器連接失敗的解決方法(僅供參考)

    訪問SQLServer數(shù)據(jù)庫失敗時,最常見的錯誤是"連接服務(wù)器失敗,SQLServer不存在或訪問被拒絕",或者"未能建立與(local)的鏈接,SQLServer不存在或訪問被拒絕",這篇文章主要給大家介紹了關(guān)于SQL?Server安裝后本地服務(wù)器連接失敗的解決方法,需要的朋友可以參考下
    2023-11-11

最新評論

灯塔市| 华宁县| 花莲县| 龙陵县| 达尔| 富蕴县| 连山| 阜城县| 丹棱县| 京山县| 高阳县| 紫阳县| 海南省| 综艺| 兴宁市| 唐海县| 淄博市| 常山县| 福建省| 焦作市| 扶绥县| 武安市| 思南县| 明光市| 城步| 长宁县| 榆树市| 威远县| 乌拉特中旗| 西安市| 吉安市| 乐清市| 景东| 阳高县| 铜陵市| 万源市| 新平| 绍兴县| 潮安县| 大邑县| 樟树市|