我有一个MS SQL Server 2005数据库.在一些过程中,我将表参数作为nvarchar(以逗号分隔)传递给存储过程,并在内部划分为单个值.我将它添加到SQL命令参数列表中,如下所示:
cmd.Parameters.Add("@Logins", SqlDbType.NVarchar).Value = "jim18,jenny1975,cosmo";
Run Code Online (Sandbox Code Playgroud)
我必须将数据库迁移到SQL Server 2008.我知道有表值参数,我知道如何在存储过程中使用它们.但我不知道如何将一个传递给SQL命令中的参数列表.有谁知道Parameters.Add程序的正确语法?或者是否有另一种传递此参数的方法?
c# sql-server stored-procedures sqlcommand table-valued-parameters
我将不得不使用SQL Server的BULK INSERT命令重写一些相当旧的代码,因为架构已经改变,而且我想到也许我应该考虑用TVP切换到存储过程,但我想知道是什么影响它可能有性能.
一些背景信息可能有助于解释我为什么问这个问题:
数据实际上是通过Web服务提供的.Web服务将文本文件写入数据库服务器上的共享文件夹,该文件夹依次执行BULK INSERT.这个过程最初是在SQL Server 2000上实现的,当时除了INSERT在服务器上丢失几百个语句之外别无选择,这实际上是原始进程并且是性能灾难.
将数据批量插入永久登台表,然后合并到更大的表中(之后将其从登台表中删除).
要插入的数据量是"大",但不是"巨大的" - 通常是几百行,在极少数情况下可能是5-10k行.因此,我的直觉是,BULK INSERT作为一个非记录操作不会产生那么大的差异(但当然我不确定,因此问题).
插入实际上是一个更大的流水线批处理过程的一部分,需要连续多次发生; 因此性能是至关重要的.
我想BULK INSERT用TVP 取代的原因是:
在NetBIOS上编写文本文件可能已经花费了一些时间,而且从架构的角度来看它非常可怕.
我相信可以(而且应该)消除临时表.它的主要原因是插入的数据需要在插入的同时用于其他几个更新,并且尝试从大量生产表进行更新比使用几乎空的分段更加昂贵表.使用TVP,参数基本上是临时表,我可以在主插入之前/之后用它做任何我想做的事情.
我几乎可以废除欺骗检查,清理代码以及与批量插入相关的所有开销.
如果服务器同时获得一些这些事务,我们无需担心登台表或tempdb上的锁争用(我们尽量避免它,但它会发生).
在将任何内容投入生产之前,我显然会对此进行分析,但我认为在我花费所有时间之前首先询问周围可能是一个好主意,看看是否有任何人有关于为此目的使用TVP的任何严厉警告.
那么 - 对于那些对SQL Server 2008足够惬意的人来说,或者至少已经对此进行了调查,那么判决是什么?对于插入,比方说,几百到几千行,经常发生,TVP切割芥末?与批量插入相比,性能是否存在显着差异?
(又名:测试结果)
最终的结果是在感觉像36阶段部署过程之后的生产中.两种解决方案都经过了广泛测试
SqlBulkCopy直接使用该类;只是让读者可以得到一个想法是什么确切地进行了测试,以消除任何怀疑这个数据的可靠性,这里是什么这个导入过程更详细的解释实际上做:
从时间数据序列开始,通常约为20-50个数据点(尽管有时可能会达到几百个);
做一大堆疯狂的处理,主要是独立于数据库.该过程是并行化的,因此(1)中的大约8-10个序列同时被处理.每个并行过程生成3个附加序列.
取所有3个序列和原始序列并将它们组合成一批.
将所有8-10个现已完成的加工任务的批次合并为一个大型超级批次.
使用BULK INSERT策略(请参阅下一步)或TVP策略(跳至步骤8)导入.
使用SqlBulkCopy该类将整个超级批处理转储到4个永久临时表中.
运行存储过程,(a)对其中两个表执行一系列聚合步骤,包括几个JOIN条件,然后(b)MERGE使用聚合和非聚合数据执行6个生产表.(成品)
要么
生成DataTable包含要合并的数据的4个对象; 其中3个包含CLR类型,遗憾的是ADO.NET TVP不能正确支持它们,因此必须将它们作为字符串表示形式推入,这会对性能造成一定影响.
将TVP馈送到存储过程,该过程基本上与(7)进行相同的处理,但是直接与接收的表一起进行.(成品)
结果相当接近,但TVP方法最终平均表现更好,即使数据少量超过1000行. …
performance bulkinsert sql-server-2008 table-valued-parameters
我正在尝试调用接受表值参数的存储过程.我知道实体框架中没有直接支持这个,但据我所知,你可以使用ExecuteStoreQuery命令off来实现ObjectContext.我有一个通用的实体框架存储库,我有以下ExecuteStoredProcedure方法:
public IEnumerable<T> ExecuteStoredProcedure<T>(string procedureName, params object[] parameters)
{
StringBuilder command = new StringBuilder();
command.Append("EXEC ");
command.Append(procedureName);
command.Append(" ");
// Add a placeholder for each parameter passed in
for (int i = 0; i < parameters.Length; i++)
{
if (i > 0)
command.Append(",");
command.Append("{" + i + "}");
}
return this.context.ExecuteStoreQuery<T>(command.ToString(), parameters);
}
Run Code Online (Sandbox Code Playgroud)
命令字符串最终如下:
EXEC someStoredProcedureName {0},{1},{2},{3},{4},{5},{6},{7}
Run Code Online (Sandbox Code Playgroud)
我试图在接受表值参数的存储过程上运行此方法,并且它会中断.我在这里读到需要的类型SqlParameter参数和表值参数需要SqlDbType设置为Structured.所以我这样做了,我得到一个错误说明:
The table type parameter p6 must have a …Run Code Online (Sandbox Code Playgroud) c# stored-procedures entity-framework table-valued-parameters ef-code-first
我创建了一个存储过程,它接受一个表值参数,该参数是一个具有int类型的单个列的表.我们的想法是简单地将一个id列表传递给存储过程,并允许sp使用数据.但是,在没有数据传入的情况下,我遇到了问题(当我有数据时,事情正常工作).我正在将List转换为IEnumerable,并将其绑定到sp的表值参数.我试图绑定一个空List,导致错误
System.ArgumentException:SqlDataRecord枚举中没有记录.要发送没有行的表值参数,请使用值的空引用.
然后我尝试绑定一个空值(我认为这是上面的消息得到的),但这只会导致一个不同的错误消息
System.NotSupportedException:不支持参数'@MainItemIdList'的DBNull值.表值参数不能是DBNull.
您似乎不能在sp声明中将表值参数声明为可为空.将空列表绑定到表值参数的正确方法是什么?
.net stored-procedures sql-server-2008 table-valued-parameters
我有一个文件(有1000万条记录),如下所示:
line1
line2
line3
line4
.......
......
10 million lines
Run Code Online (Sandbox Code Playgroud)
所以基本上我想在数据库中插入1000万条记录.所以我读了文件并将其上传到SQL Server.
C#代码
System.IO.StreamReader file =
new System.IO.StreamReader(@"c:\test.txt");
while((line = file.ReadLine()) != null)
{
// insertion code goes here
//DAL.ExecuteSql("insert into table1 values("+line+")");
}
file.Close();
Run Code Online (Sandbox Code Playgroud)
但插入需要很长时间.如何使用C#在尽可能短的时间内插入1000万条记录?
更新1:
批量插入:
BULK INSERT DBNAME.dbo.DATAs
FROM 'F:\dt10000000\dt10000000.txt'
WITH
(
ROWTERMINATOR =' \n'
);
Run Code Online (Sandbox Code Playgroud)
我的表如下:
DATAs
(
DatasField VARCHAR(MAX)
)
Run Code Online (Sandbox Code Playgroud)
但我得到以下错误:
Msg 4866,Level 16,State 1,Line 1
批量加载失败.第1行第1列的数据文件中的列太长.验证是否正确指定了字段终止符和行终止符.消息7399,级别16,状态1,行1
链接服务器"(null)"的OLE DB提供程序"BULK"报告错误.提供商未提供有关错误的任何信息.消息7330,级别16,状态2,行1
无法从OLE DB提供程序"BULK"获取链接服务器"(null)"的行.
下面的代码工作:
BULK INSERT DBNAME.dbo.DATAs
FROM 'F:\dt10000000\dt10000000.txt'
WITH
(
FIELDTERMINATOR = '\t',
ROWTERMINATOR …Run Code Online (Sandbox Code Playgroud) 当我点击TVP时,我没有得到像'ALTER TO'这样的选项
这个来自SQL Server 2008 BOL的页面讨论了CLR存储过程,并有一个标记为"表值参数"的部分,讨论了它们如何有利.这很好 - 我喜欢在我的CLR过程中使用TVP,但不幸的是,这似乎是宇宙中唯一可能的参考,并且该部分没有描述语法是什么(也没有进一步的信息链接在该段末尾)
当然,我可以很容易地找到如何从T-SQL过程中使用TVP的描述,或者如何一般地进行CLR过程.但是写一个带有TVP的CLR过程?没有.这是非常不寻常的,因为将多行数据传递到存储过程是一个流行的问题.
这让我想知道该页面上是否存在该部分是错误的.有人请告诉我它不是,并指出更多信息/示例.
[编辑]
当我遇到这个时,我也准备把它发布到MS论坛之一,这似乎是棺材中的最后一个钉子.看起来无法完成.
clr stored-procedures sql-server-2008 table-valued-parameters
我想将一组id传递给将使用NHibernate映射的存储过程.这种技术是在Sql Server 2008中引入的(更多信息在这里=> 表值参数).我只是不想在nvarchar参数中传递多个ID ,然后在SQL Server端切断它的值.
我在SQL Server 2012中有一个表值参数定义为:
CREATE TYPE [dbo].[TVP] AS TABLE (
[Id] [int] NOT NULL,
[FieldName] [nvarchar](100) NOT NULL,
[Value] [sql_variant] NOT NULL
)
Run Code Online (Sandbox Code Playgroud)
我在C#中使用代码看起来大致如下所示:
var mdItems = new DataTable();
mdItems.Columns.Add("Id", typeof(int));
mdItems.Columns.Add("FieldName", typeof(string));
mdItems.Columns.Add("Value", typeof(object));
mdItems.Rows.Add(new object[] {2, "blah", "value"}); //'value' is usually a string
SqlCommand sqlCommand = conn.CreateCommand();
sqlCommand.CommandText = "[WriteFieldValues]";
sqlCommand.CommandType = CommandType.StoredProcedure;
sqlCommand.Parameters.AddWithValue("@FieldValues", mdItems);
sqlCommand.ExecuteNonQuery();
Run Code Online (Sandbox Code Playgroud)
然后,我在ExecuteNonQuery调用SQL Server时收到以下错误:
不支持"值"列的类型.类型是'对象'
我发现有人在3年前遇到了同样的问题,当时它被认定为已知的Microsoft bug.但是,该错误的链接已被破坏.有谁知道是否有关于错误状态或潜在解决方法的最新信息?就目前而言,这个错误确实会破坏sql_variant字段的价值.
c# sql-server sql-variant table-valued-parameters sql-server-2012
我们一直在使用用户定义的表类型将整数列表传递给我们的存储过程.
然后我们使用它们连接到存储过程查询中的其他表.
例如:
CREATE PROCEDURE [dbo].[sp_Name]
(
@Ids [dbo].[OurTableType] READONLY
)
AS
SET Nocount ON
SELECT
*
FROM
SOMETABLE
INNER JOIN @Ids [OurTableType] ON [OurTableType].Id = SOMETABLE.Id
Run Code Online (Sandbox Code Playgroud)
在使用更大的数据集时,我们发现这方面的表现很差.
我们用来加快速度的一种方法是将内容转储到临时表中,然后将其加入.
例如:
CREATE PROCEDURE [dbo].[sp_Name]
(
@Ids [dbo].[OurTableType] READONLY
)
AS
SET Nocount ON
CREATE TABLE #TempTable(Id INT)
INSERT INTO #TempTable
SELECT Id from @Ids
SELECT
*
FROM
SOMETABLE
INNER JOIN #TempTable ON #TempTable.Id = SOMETABLE.Id
DROP TABLE #TempTable
Run Code Online (Sandbox Code Playgroud)
这确实显着提高了性能,但我希望对这种方法以及我们未考虑的任何其他后果有所了解.关于为什么这改善性能的解释也可能是有用的.
NB有时我们可能需要传递的不仅仅是一个整数,因此我们不使用逗号分隔列表或类似的东西.
t-sql sql-server user-defined-types table-valued-parameters sql-server-2008-r2
sql-server ×6
c# ×4
bulkinsert ×2
t-sql ×2
.net ×1
clr ×1
import ×1
nhibernate ×1
performance ×1
sql-variant ×1
sqlcommand ×1