首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 数据库 > SQL Server >

SQL Server 高性能写下的一些总结

2013-01-28 
SQL Server 高性能写入的一些总结-- -- Author:JKhuang--

SQL Server 高性能写入的一些总结

-- =============================================-- Author:        JKhuang-- Create date: 7/8/2012-- Description:    A table stores the user information.-- =============================================CREATE TABLE [dbo].[jk_users](     -- This is the reference to Users table, it is primary key.    [ID] [bigint] IDENTITY(1,1) NOT NULL,    [user_login] [varchar](60) NOT NULL,    [user_pass] [varchar](64) NOT NULL,    [user_nicename] [varchar](50) NOT NULL,    [user_email] [varchar](100) NOT NULL,    [user_url] [varchar](100) NOT NULL,    -- This field get the default from function GETDATE().    [user_registered] [datetime] NOT NULL CONSTRAINT [DF_jk_users_user_registered]  DEFAULT (getdate()),    [user_activation_key] [varchar](60) NOT NULL,    [user_status] [int] NOT NULL CONSTRAINT [DF_jk_users_user_status]  DEFAULT ((0)),    [display_name] [varchar](250) NOT NULL  

//// Creates a database connection.var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLCONN1"].ToString());conn.Open();//// This is a massive SQL injection vulnerability, //// don't ever write your own SQL statements with string formatting!string sql = String.Format(      @"INSERT INTO jk_users (user_login, user_pass, user_nicename, user_email, user_status,display_name, user_url, user_activation_key)        VALUES ('{0}', '{1}', '{2}', '{3}', '{4}', '{5}', '{6}', '{7}')",      userLogin, userPass, userNicename, userEmail, userStatus, displayName, userUrl, userActivationKey);var cmd = new SqlCommand(sql, conn);cmd.ExecuteNonQuery();//// Because this call to Close() is not wrapped in a try/catch/finally clause, //// it could be missed if an exception occurs above.  Don't do this!conn.Close(); 

//// Creates a database connection.var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLCONN1"].ToString());conn.Open();//// This is a massive SQL injection vulnerability, //// don't ever write your own SQL statements with string formatting!string sql = String.Format(      @"INSERT INTO jk_users (user_login, user_pass, user_nicename, user_email, user_status,display_name, user_url, user_activation_key)        VALUES ('{0}', '{1}', '{2}', '{3}', '{4}', '{5}', '{6}', '{7}')",      userLogin, userPass, userNicename, userEmail, userStatus, displayName, userUrl, userActivationKey);var cmd = new SqlCommand(sql, conn);cmd.ExecuteNonQuery();//// If throws an exception on cmd dispose.cmd.Dispose();//// conn can't be disposed.conn.Close();conn.Dispose();

SqlCommand cmd = null;SqlConnection conn = null;try{    //// Creates a database connection.    conn = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLCONN1"].ToString());    conn.Open();    //// This is a massive SQL injection vulnerability,     //// don't ever write your own SQL statements with string formatting!    string sql = String.Format(          @"INSERT INTO jk_users (user_login, user_pass, user_nicename, user_email, user_status,display_name, user_url, user_activation_key)        VALUES ('{0}', '{1}', '{2}', '{3}', '{4}', '{5}', '{6}', '{7}')",          userLogin, userPass, userNicename, userEmail, userStatus, displayName, userUrl, userActivationKey);    cmd = new SqlCommand(sql, conn);    cmd.ExecuteNonQuery();}finally{    //// Regardless of whether there is an exception,    //// we will dispose the resource.     if (cmd != null) cmd.Dispose();    if (conn != null) conn.Dispose(); 

string sql = String.Format(      @"INSERT INTO jk_users (user_login, user_pass, user_nicename, user_email, user_status,display_name, user_url, user_activation_key)        VALUES ('{0}', '{1}', '{2}', '{3}', '{4}', '{5}', '{6}', '{7}')",              userLogin, userPass, userNicename, userEmail, userStatus, displayName, userUrl, userActivationKey);//// Creates a database connection.using (var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLCONN1"].ToString()))using (var cmd = new SqlCommand(sql, conn)){    //// Your code here. 

//// Creates a database connection.using (var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLCONN1"].ToString())){    conn.Open();    string sql = string.Format(             @"INSERT INTO jk_users (user_login, user_pass, user_nicename, user_email,                 user_status,display_name, user_url, user_activation_key)");    using (var cmd = new SqlCommand(sql, conn))    {        //// Parameterized SQL to defense injection attacks        cmd.Parameters.Add("@user_login", userLogin);        cmd.Parameters.Add("@user_pass", userPass);        cmd.Parameters.Add("@user_nicename", userNicename);        cmd.Parameters.Add("@user_email", userEmail);        cmd.Parameters.Add("@user_status", userStatus);        cmd.Parameters.Add("@display_name", displayName);        cmd.Parameters.Add("@user_url", userUrl);        cmd.Parameters.Add("@user_activation_key", userActivationKey);        cmd.ExecuteNonQuery();    } 

    //// calc insert 10000 records consume time.    var sw = Stopwatch.StartNew();    //// Creates a database connection.    using (var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLCONN2"].ToString()))    {        conn.Open();        int cnt = 0;        while (cnt++ < 10000)        {            string sql = string.Format(@"INSERT INTO jk_users                  (user_login, user_pass, user_nicename, user_email, user_status,display_name, user_url, user_activation_key)                 VALUES (@user_login, @user_pass, @user_nicename, @user_email, @user_status, @display_name, @user_url, @user_activation_key)");            using (var cmd = new SqlCommand(sql, conn))            {                //// Parameterized SQL to defense injection attacks                cmd.Parameters.Add("@user_login", userLogin);                cmd.Parameters.Add("@user_pass", userPass);                cmd.Parameters.Add("@user_nicename", userNicename);                cmd.Parameters.Add("@user_email", userEmail);                cmd.Parameters.Add("@user_status", userStatus);                cmd.Parameters.Add("@display_name", displayName);                cmd.Parameters.Add("@user_url", userUrl);                cmd.Parameters.Add("@user_activation_key", userActivationKey);                cmd.ExecuteNonQuery();            }        }    }    sw.Stop();} 

-- =============================================-- Author:        JKhuang-- Create date: 08/16/2012-- Description:    Creates stored procedure to insert-- data into table jk_users.-- =============================================ALTER PROCEDURE [dbo].[SP_Insert_jk_users]     @user_login varchar(60),     @user_pass varchar(64),     @user_nicename varchar(50),     @user_email varchar(100),     @user_url varchar(100),     @user_activation_key varchar(60),    @user_status int,     @display_name varchar(250)     ASBEGIN    SET NOCOUNT ON;-- The stored procedure allows SQL server to avoid virtually all parser workINSERT INTO jk_users        (user_login, user_pass, user_nicename, user_email, user_status,display_name, user_url, user_activation_key, user_registered)       VALUES (@user_login, @user_pass, @user_nicename, @user_email, @user_status, @display_name, @user_url, @user_activation_key, GETDATE());END 

    //// calc insert 10000 records consume time.    var sw = Stopwatch.StartNew();    //// Creates a database connection.    using (var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLCONN2"].ToString()))    {        conn.Open();        int cnt = 0;        SqlTransaction trans = conn.BeginTransaction();        while (cnt++ < 10000)        {            using (var cmd = new SqlCommand("SP_Insert_jk_users", conn))            {                //// Parameterized SQL to defense injection attacks                cmd.CommandType = CommandType.StoredProcedure;                //// Uses transcation to batch insert data.                //// To avoid lock and connection overhead.                cmd.Transaction = trans;                cmd.Parameters.Add("@user_login", userLogin);                cmd.Parameters.Add("@user_pass", userPass);                cmd.Parameters.Add("@user_nicename", userNicename);                cmd.Parameters.Add("@user_email", userEmail);                cmd.Parameters.Add("@user_status", userStatus);                cmd.Parameters.Add("@display_name", displayName);                cmd.Parameters.Add("@user_url", userUrl);                cmd.Parameters.Add("@user_activation_key", userActivationKey);                cmd.ExecuteNonQuery();            }        }        //// If no exception, commit transcation.        trans.Commit();    }    sw.Stop();}

/// <summary>/// Gets the data rows./// </summary>/// <returns></returns>DataRow[] GetDataRows(int rowCnt){    //// Creates a custom table.    var dt = new DataTable("jk_users");    dt.Columns.Add(new DataColumn("user_login", typeof(System.String)));    dt.Columns.Add(new DataColumn("user_pass", typeof(System.String)));    dt.Columns.Add(new DataColumn("user_nicename", typeof(System.String)));    dt.Columns.Add(new DataColumn("user_email", typeof(System.String)));    dt.Columns.Add(new DataColumn("user_url", typeof(System.String)));    dt.Columns.Add(new DataColumn("user_registered", typeof(System.DateTime)));    dt.Columns.Add(new DataColumn("user_activation_key", typeof(System.String)));    dt.Columns.Add(new DataColumn("user_status", typeof(System.Int32)));    dt.Columns.Add(new DataColumn("display_name", typeof(System.String)));    //// Initializes data row.    var dr = dt.NewRow();    dr["user_login"] = "JK_RUSH";    dr["user_pass"] = "D*<1C2jK#-";    dr["user_nicename"] = "JK";    dr["user_email"] = "jkhuang@gamil.com";    dr["user_status"] = 1;    dr["display_name"] = "JK_RUSH";    dr["user_url"] = "http://www.cnblogs.com/rush";    dr["user_activation_key"] = "347894102386";    dr["user_registered"] = DateTime.Now;    //// Creates data row array.    var dataRows = new DataRow[rowCnt];    for (int i = 0; i < rowCnt; i++)    {        dataRows[i] = dr;    }    return dataRows;}

//// Creates 10001 data rows. var dataRows = GetDataRows(10001);var sw = Stopwatch.StartNew();//// Creates a database connection.using (var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLCONN2"].ToString())){    conn.Open();    using (var bulkCopy = new SqlBulkCopy(conn))    {        //// Maping the data columns.        bulkCopy.ColumnMappings.Add("user_login", "user_login");        bulkCopy.ColumnMappings.Add("user_pass", "user_pass");        bulkCopy.ColumnMappings.Add("user_nicename", "user_nicename");        bulkCopy.ColumnMappings.Add("user_email", "user_email");        bulkCopy.ColumnMappings.Add("user_url", "user_url");        bulkCopy.ColumnMappings.Add("user_registered", "user_registered");        bulkCopy.ColumnMappings.Add("user_activation_key", "user_activation_key");        bulkCopy.ColumnMappings.Add("user_status", "user_status");        bulkCopy.ColumnMappings.Add("display_name", "display_name");        bulkCopy.DestinationTableName = "dbo.jk_users";        //// Insert data into datatable.        bulkCopy.WriteToServer(dataRows);    }    sw.Stop();}

图5 数据写入时间

-- =============================================-- Author:        JKhuang-- Create date: 08/16/2012-- Description:    Declares a user table paramter.-- =============================================CREATE TYPE jk_users_bulk_insert AS TABLE (    user_login varchar(60),    user_pass varchar(64),    user_nicename varchar(50),    user_email varchar(100),    user_url varchar(100),    user_activation_key varchar(60),    user_status int,    display_name varchar(250)) 

-- =============================================-- Author:        JKhuang-- Create date: 08/16/2012-- Description:    Creates a stored procedure, receive-- a jk_users_bulk_insert argument.-- =============================================CREATE PROCEDURE sp_insert_jk_users @usersTable jk_users_bulk_insert READONLY ASINSERT INTO jk_users (user_login, user_pass, user_nicename, user_email, user_url, user_activation_key, user_status, display_name, user_registered) SELECT user_login, user_pass, user_nicename, user_email, user_url, user_activation_key, user_status, display_name, GETDATE() FROM @usersTable 

var sw = Stopwatch.StartNew();using (var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLCONN2"].ToString())){    conn.Open();    //// Invokes the stored procedure.    using (var cmd = new SqlCommand("sp_insert_jk_users", conn))    {        cmd.CommandType = CommandType.StoredProcedure;        //// Adding a "structured" parameter allows you to insert tons of data with low overhead        var param = new SqlParameter("@userTable", SqlDbType.Structured) { Value = dt };        cmd.Parameters.Add(param);        cmd.ExecuteNonQuery();    }}sw.Stop(); 

现在,我们重新执行写入操作发现写入效率与SqlBulkCopy相当。

1.1.3总结

本文通过博客系统用户表设计的例子,介绍我们在设计过程中容易犯 的错误和代码的缺陷,例如:SQL注入、数据库资源释放等问题;进而使用一些常用的代码优化技巧对代码进行优化,并且通过分析数据库写入的性能开销(连接 时间、解析器、数据库连接、约束处理、VARCHAR和磁盘IO),我们使用存储过程、数据库事务、SqlBulkCopy和表参数等方式降低数据库的开 销。

热点排行