剛進一家公司,還在熟悉他們的代碼,看到他們經常在for循環中執行數據的插入,修改以及刪除操作,接觸到Entity Framework時候,它里面有個SavaChange()方法,EF里面的執行數據庫操作只有通過調用該方法才會真正的到數據庫中執行。所以從中得到啟發:我們也可以將Insert/Update/Delete操作批量進行執行,減少數據庫訪問次數,提高執行效率。
首先附上SqlHelper部分代碼
private readonly static string conStr = ConfigurationManager.ConnectionStrings["sql"].ConnectionString; public static int ExecuteNonQuery(string sql, CommandType type, params SqlParameter[] pars) { using (SqlConnection con = new SqlConnection(conStr)) { using (SqlCommand cmd = new SqlCommand(sql, con)) { cmd.CommandType = type; if (pars != null && pars.Length > 0) { cmd.Parameters.AddRange(pars); } con.Open(); return cmd.ExecuteNonQuery(); } } }
像數據庫中重復插入十萬條數據
class Program { static void Main(string[] args) { Stopwatch watch = new Stopwatch(); watch.Start(); #region 重復訪問數據庫插入 for (int i = 0; i < 100000; i++) { string sql = "insert into TPerson values(@Name,@Age)"; SqlParameter[] pams = new SqlParameter[]{ new SqlParameter("@Name","sj"+i), new SqlParameter("@Age",i) }; SqlHelper.ExecuteNonQuery(sql, System.Data.CommandType.Text, pams); } #endregion watch.Stop(); Console.WriteLine("所執行時間:" + watch.ElapsedMilliseconds); Console.Read(); } }
所執行時間:
我們可以通過查看SQL Server Profier
他在數據庫中實際執行了四十萬條指令,大概算了下大約每秒能插入300到400條數據
通過循環拼sql,多次批量插入數據庫執行
class Program { static void Main(string[] args) { Stopwatch watch = new Stopwatch(); watch.Start(); #region 拼sql語句多次執行 for (int i = 0; i < 1000; i++) { StringBuilder sb = new StringBuilder(); List<SqlParameter> parameterList = new List<SqlParameter>(); for (int j = 0; j < 100; j++) { sb.Append(string.Format(" insert into TPerson values(@Name{0},@Age{0}); ", j)); parameterList.Add(new SqlParameter("@Name" + j, "sj" + j)); parameterList.Add(new SqlParameter("@Age" + j, j)); } SqlHelper.ExecuteNonQuery(sb.ToString(), System.Data.CommandType.Text, parameterList.ToArray()); } #endregion watch.Stop(); Console.WriteLine("所執行時間:" + watch.ElapsedMilliseconds); Console.Read(); } }
執行的效果:
同樣我們查看SQL Server Profier
執行了大概4000條指令,算了下大概每秒可以插入1500條數據
當然不是內部循環越多就越好的(對應的就是代碼中的j越大),SqlParameter支持的參數最多2100個,大概j=200時候效率相對來說會更高點,當然可能是由於參數制約吧,有興趣的朋友可以試試。
如果i=500,j=200時候,效果如下:
總結
通過上述實驗,我們可以發現當出現大量操作數據庫(insert/update/delete)時候,我們可以不再for循環中直接訪問數據庫,操作執行。我們可以通過循環一定次數,拼裝sql,以及SqlParameter,這樣執行效率將大大提高。我有一個想法,我們可以自己開發一個組件,這個組件功能是一個隊列,用於存放這些sql語句,我們寫的sql語句(Insert/Update/Delete)都放到該隊列中,該隊列每隔段時間進行數據庫訪問。不過這樣帶來的問題是如何將隊列中執行后的結果返回到調用的地方。
后來聽同事提到SqlBulkCopy這個類可以批量進行數據插入,網上搜索下總結下他的功能:單獨批量復制操作,可將數據從一個數據源移動到SQL Server表中。也可執行多個批量復制操作。在數據庫事務中可執行批量復制操作。所以還是有一些局限性的。希望能夠得到大家的看法,謝謝。