我有一个存储过程将数据插入3个表(UPSERTS),并且有一些逻辑。 (IF-THEN-ELSE)
我需要使用不同的参数执行此Sproc数百万次(来自C#应用程序),我需要它快速。
最好的方法是什么?
除了Lucene或Sql Server FTS之外,有没有人知道开源(或不是)现成的文档索引器?
*我正在尝试构建一个文档word-index。对于文档中的每个单词,我将单词,docID和单词位置插入DB中。
例如,对于100个文档,这发生了100000次。
The Sproc :要插入3个表,每个表都要进行一次UPSERT。
C#app :
using (SqlConnection con = new SqlConnection(_connectionString))
{
con.Open();
SqlTransaction trans = con.BeginTransaction();
SqlCommand command = new SqlCommand("add_word", con, trans);
command.CommandType = System.Data.CommandType.StoredProcedure;
string[] TextArray;
for (int i = 0; i < Document.NumberOfFields; i++)
{
...
Addword(..., command); <---- this updates parameters with new values and ExecuteNonQuery.
}
}
我忘了提一下,这段代码在Sql Server中产生死锁。我不知道为什么会这样。
答案 0 :(得分:3)
删除正在加载的表上的所有索引,然后在加载完成后重新添加它们。这将阻止每次更改的大量颠簸/重新索引。
确保数据库在加载之前已经分配了足够的物理文件空间,因为在加载时不必花时间从文件系统中不断地抓取它。通常,数据库设置为在完全时增长10%,此时sql server会阻止查询,直到分配更多空间。当你加载你正在谈论的数据量时,sql将不得不做很多阻塞。
如果可能,请查看批量加载/批量复制。
在代码中执行所有IF THEN ELSE逻辑。只需将存储的实际值发送到s'proc即可。你甚至可以运行两个线程。一个用于评估数据并将其排队,另一个用于将队列写入DB服务器。
查看Off The Shelf程序,这些程序完全按照索引文档进行操作。他们很可能已经解决了这些问题。
尽可能摆脱交易要求。尽量保持s'proc调用尽可能简单。
查看您是否可以限制要存储的字词。例如,如果您不关心单词“it”,“as”,“I”等,则在调用s'proc之前将其过滤掉。
答案 1 :(得分:2)
如果要快速从C#批量INSERT数据,请查看SqlBulkCopy类(从.NET 2.0开始)。
答案 2 :(得分:1)
这可能是一个非常通用的要求 - 为了使程序快速,我们需要查看它并了解你的db-schema。
另一方面,如果你想知道尽可能快地执行相同(非优化或优化)程序的最佳方法,通常最好的方法是做某种缓存< / strong>在客户端上,尽可能少地调用该过程来批量操作。
如果这是循环,人们通常做的是 - 而不是每次迭代调用过程 - 构建/填充一些缓存数据结构,当循环退出时(或任何给定数量的循环)将调用存储过程如果你需要更经常地发生这种情况)批处理你缓存的操作(即你可以将一个xml字符串传递给你的sp然后解析它,将这些东西放在临时表中然后从那里去 - 你可以节省一个整体很多这样的开销)。
另一种常见的解决方案是使用SqlServer 批量操作。
回到存储过程 - 请注意优化T-SQL和db-schema(带索引等)可以对您的性能产生光辉的影响。
答案 3 :(得分:1)
这似乎是一种基本的方法,但它应该有效,而且应该很快。您可以使用SQL语句列表生成一个巨大的文本文件,然后从命令行运行它。如果我没有弄错,应该可以使用GO语句批处理命令。或者,您可以直接从应用程序将多个SQL命令连接为字符串并批量执行它们。看起来你要做的是一次性任务,数据不是直接作为用户输入。所以你应该能够自己处理逃避。
我确信有更复杂的方法可以做到这一点(SqlBulkCopy
看起来是一个好的开始),所以请将此视为一个建议。我会花一些时间来调查是否有更优雅的方式更好的方法。
另外,我会确保存储过程中的逻辑尽可能简单,并且表中没有任何索引。它们应该在以后添加。
答案 4 :(得分:1)
尝试使用XML来做到这一点。
你只需执行一次:
示例:
DECLARE @XMLDoc XML
SET @XMLDoc = '<words><word>test</word><word>test2</word></words>'
CREATE PROCEDURE add_words
(
@XMLDoc XML
)
AS
DECLARE @handle INT
EXEC sp_xml_preparedocument @handle OUTPUT, @XMLDoc
INSERT INTO TestTable
SELECT * FROM OPENXML (@handle, '/words', 2) WITH
(
word varchar(100)
)
EXEC sp_xml_removedocument @handle
答案 5 :(得分:0)
如果您正在尝试优化速度,请考虑简单地升级SQL Server硬件。在服务器中放置一些RAM和超快的RAID可能是提高查询速度的最具成本效益的长期解决方案。与开发人员时间相比,硬件相对便宜。
听取杰夫阿特伍德的话:
答案 6 :(得分:0)
在这种情况下,与数据库的通信可能是瓶颈,特别是如果数据库在另一台机器上。我建议将整个文档发送到数据库并编写一个将其拆分为单词的sproc,或者使用sql-server托管的托管代码。
答案 7 :(得分:0)
假设这是一个不会在多个用户之间发生争用的应用,请尝试使用此方法:
这将消除调用SP数百万次的开销,并且可以连接表中参数的插入(“INSERT INTO foo(v)VALUE('bar'); INSERT INTO foo(v)VALUE ('bar2'); INSERT INTO foo(v)VALUE('bar3');“)。
缺点:SP需要很长时间才能执行,并且不会有任何进度反馈,这不是非常用户友好的。
答案 8 :(得分:0)
要将大量数据移动到服务器,如果您在2008年,请使用SqlBulkCopy或表值参数。如果您需要速度,请不要每行执行一次存储过程,开发一个基于集合的处理所有数据的集合(或一大批)行。
答案 9 :(得分:-1)
- 自问题编辑以来编辑过。
最大的问题是确保正确调整存储过程。您的C#代码与您获得它的速度一样快。