所以快速总结一下,我有一个sqlServer
数据库(使用SSMS来工作),并且它有一个带有 order_num 列的表,然后是一个描述列。
例如16548221587 | Small hairbrush.
我在 order_num 列上有索引。
然后我有了一个VB.net应用程序,基本上我希望它允许用户放置一个.txt文件,其中包含大量的 order_nums (> 150,000,每行1个)及其内容这样做是逐行读取这些内容,然后搜索数据库,将所有内容添加到临时表中,然后streamwrites
将其添加到“结果” .txt文件中。
关于这个问题的标题,我问它是因为我将在下面发布的代码有效!我在阅读和查找时进行计时,并在0.427秒的搜索时将每个查找插入到临时表中,但将其与150,000条记录一起进行查找需要16个小时以上!因此,这就是我想知道的是我是否正在以一种混乱的方式进行此操作,或者我期望太多的读取/查找和检索大量记录并期望它能更快地运行?
If System.IO.File.Exists(TextBox2.Text) Then
'read in file list of order numbers to search
result = From n In System.IO.File.ReadLines(TextBox2.Text)
Where n.Length = 13
Select n.Substring(0, 13)
Else
MessageBox.Show("The file path you entered seems to be invalid. Please try again.")
Exit Sub
End If
For Each word As String In result
Dim cmd As New SqlCommand("dbo.OrdersToTemp", con)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.Add("@OrderNum", SqlDbType.NVarChar).Value = word.ToString()
cmd.CommandTimeout = 3000
cmd.ExecuteNonQuery()
Next
Using sw As New StreamWriter(TextBox2.Text.Substring(0, TextBox2.TextLength - 4) + "-results.txt")
Dim retrieveResults As New SqlCommand("dbo.GetResults", con)
retrieveResults.CommandType = CommandType.StoredProcedure
retrieveResults.CommandTimeout = 3000
Using RDR = retrieveResults.ExecuteReader
Do While RDR.Read
OrderDescription = RDR("Description").ToString()
sw.WriteLine(OrderDescription )
Loop
End Using
End Using
更新
我已经对此提出了一些建议,现在我用sqlbulkcopy将需要搜索到temp表中的order_nums进行,这是相当快的。然后,我正在使用诸如
的查询SELECT o.order_num, description
from OrderTable o
join TempOrderIdTable t on t.order_num = o.order_num
但是,即使仅获得170个结果也要花费30秒,这在我看来还是相当缓慢,这似乎仍然很慢。我在order_table的order_num上放了一个聚集索引,而在temp表上基本上只是.txt文件,但在sql表上却没有临时索引。
更新2
所以就像我说的,我现在在OrderTable上有一个非聚集索引(orderNo包括描述),在TempTable上有一个聚集索引(Order_num),但是任何类型的联接或交叉应用等都需要花费33秒钟以上的时间才能基本联接100 OrderNum并仅返回170,这仍然如此缓慢。这是我正在尝试的联接:
select o.Order_num, t.description
from Temp_data o
join OrderTable on t.Order_num= o.Order_num
select x.Order_num, x.description
from OrderTable x
where Order_num in (select Order_num from Temp_data)
select x.Order_num,x.description
from OrderTable x
cross apply (select o.Order_num from Temp_data o where o.Order_num= x.Order_num) ord
已解决 因此,这是我作为最后一点的白痴,当我制作临时表时,我基本上都是正确的,我不小心将Column设置为nvarchar,而在实际的OrderTable中,它只是order_num的varchar列。抱歉,我半睡着了!
答案 0 :(得分:3)
代码的问题是您执行此SQL命令150k次。那永远都不会奏效(快速)。
您可以做的是首先从文件中读取150k值,然后使用SqlBulkCopy
插入表for example as shown in this SO answer中。基本上,您可以在vb.net代码中执行dbo.OrdersToTemp
过程,只需一次即可,而不是一次只行。给定当前查询的延迟时间,最多最多需要几秒钟。
对于以下查询:
SELECT o.order_num, description
from OrderTable o
join TempOrderIdTable t on t.order_num = o.order_num
我假设OrderTable
可以每个order_num
包含多个记录(您提到要为100个订单返回170行),您可以这样使用索引:
CREATE INDEX ix ON OrderTable (order_num) INCLUDE (description)
如果文件中的订单号是唯一的(并且可以确保唯一性):
CREATE UNIQUE CLUSTERED INDEX ux ON TempOrderIdTable (order_num);
如果您的SQL Server版本支持该索引,则可以使用WITH (DATA_COMPRESSION = PAGE)
压缩索引,但这需要企业许可证(或开发人员许可证,但不能在生产环境中使用该许可证)。
答案 1 :(得分:1)
我不知道您在命令中使用的存储过程的结构,但我想大多数时候SQL Server上的操作以及应用程序和SQL Server之间的通信会占用大多数时间。因此,在那里考虑进行优化-像一次将所有数字发送给程序一样。您不必将过程调用xy次。 并尝试查看存储过程的执行计划-有什么可以改进的地方吗?
答案 2 :(得分:1)
我建议进行以下优化。
首先,直接从txt文件Bulk insert
进入临时订单ID表。如果每行中有一个order_num
,则可以。
BULK INSERT TempOrderIdTable
FROM 'C:\data\orderids.txt'
WITH (FIRSTROW = 1,
FIELDTERMINATOR = ',',
ROWTERMINATOR='\n' );
要使bulk insert
正常工作,SQL服务器必须可以在SQL Server计算机上或通过网络上的共享位置访问该文件。
第二,运行查询以通过加入临时订单ID表来一次性获得所有描述:
SELECT o.order_num, description
from OrderTable o
join TempOrderIdTable t on t.order_num = o.order_num
现在您可以将结果分为两个步骤。
答案 3 :(得分:1)
仅供以后参考(批量复制和索引无疑是答案)... 不要为循环的每次迭代创建命令,不要在每次迭代中添加参数并设置命令的属性。每个循环都相同。只有参数的值会改变。
Dim cmd As New SqlCommand("dbo.OrdersToTemp", con)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.Add("@OrderNum", SqlDbType.NVarChar)
cmd.CommandTimeout = 3000
For Each word As String In Result
cmd.Parameters("@OrderNum").Value = word
cmd.ExecuteNonQuery()
Next