关于为什么不推荐使用用户定义表类型的说明
2012-09-21 14:31 leo.wl2020 阅读(345) 评论(0) 收藏 举报对于用户定义表类型,它实际上并不能提高性能,会觉得它看起来高效的原因,是因为在程序中使用这个种类型的参数的时候,可以把 DataTable 做为参数直接传递给存储过程(看起来非常简洁)
但实际上去Trace其行为,会发现其实它相当于把 DataTable 的值包装成了 insert 语句,而不是真正的把数据做为块传给存储过程
DBA这边的建议是
1.对于少量数据,我们建议拼成 xml ,存储过程里面做解析(附件有一个开发那边提供的测试,对于少量数据,不足1万条,xml解析的性能并不差).
2.对于大量数据,我们建立使用SqlBulkInsert 来处理.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
// 批量数据的源表,存放被用于批量处理的数据
DataTable tbSrouce = new DataTable("SourceData");
tbSrouce.Columns.Add("id", Type.GetType("System.Int32"));
tbSrouce.Columns.Add("name", Type.GetType("System.String"));
tbSrouce.Rows.Add(1, "aaa");
//批量数据导入临时表,并用于后续处理
using (SqlConnection connTarget = new SqlConnection(@"Data Source=127.0.0.1;Initial Catalog=tempdb;Integrated Security=SSPI;"))
{
connTarget.Open();
// 用于数据处理的 command.
using (SqlCommand cmdProcess = new SqlCommand())
{
cmdProcess.Connection = connTarget;
//1. 创建用于存储批量处理数据的临时表
cmdProcess.CommandType = CommandType.Text;
cmdProcess.CommandText = @"CREATE TABLE #tb(id int, name nvarchar(50));";
cmdProcess.ExecuteNonQuery();
//2. 将批量处理所需要的数据导入临时表
using (var bulkCopy = new SqlBulkCopy(connTarget))
{
bulkCopy.BatchSize = 10000;
bulkCopy.BulkCopyTimeout = 9000;
// bulkCopy.NotifyAfter = 10000; // 如果要确认批量写入进度,可以设置这个,并且通过 SqlRowsCopied 事件得到进度信息
bulkCopy.DestinationTableName = "#tb"; //批量导入的目标表,注意与前面创建临时表的语句中的临时表名一致
bulkCopy.WriteToServer(tbSrouce); // 将指定的数据写入目标表
}
//3. 使用批量数据做后续处理,这些仅查询记录数
//如果是存储过程中使用,则直接在存储过程中访问临时表即可
cmdProcess.CommandText = "SELECT COUNT(*) FROM #tb;";
Console.WriteLine(cmdProcess.ExecuteScalar());
}
Console.ReadLine();
}
}
}
}
USE tempdb; GO SELECT TOP 500000 id = IDENTITY(int, 1, 1), A.* INTO DBO.tb FROM sys.all_columns A WITH(NOLOCK), sys.all_columns B WITH(NOLOCK) GO ALTER TABLE dbo.tb ADD PRIMARY KEY( id ); CREATE INDEX IX_column_id ON dbo.tb( column_id ); GO SET STATISTICS IO ON; SET STATISTICS TIME ON; GO -- 推荐的方式(性能开销比较稳定) WITH ID AS( SELECT __row_id = ROW_NUMBER() OVER(order by id DESC), id FROM dbo.tb WITH(NOLOCK) WHERE column_id = 1 ) SELECT ID.__row_id, DATA.* FROM ID INNER JOIN dbo.tb DATA WITH(NOLOCK) ON DATA.id = ID.id WHERE ID.__row_id BETWEEN 5000 AND 5100 ; GO -- 传统的方式 WITH DATA AS( SELECT __row_id = ROW_NUMBER() OVER(order by id DESC), * FROM dbo.tb WITH(NOLOCK) WHERE column_id = 1 ) SELECT * FROM DATA WHERE __row_id BETWEEN 5000 AND 5100 ; GO SET STATISTICS TIME OFF; SET STATISTICS IO OFF; GO DROP TABLE dbo.tb;
作者:HackerVirus
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息:HackerVirus@2013
浙公网安备 33010602011771号