我是不耐烦还是不高效?

问题描述 投票:0回答:4

总而言之,我有一个sqlServer数据库(使用SSMS来处理它),它有一个带有order_num列的表,然后是一个描述列。例如16548221587 | Small hairbrush.我在order_num列上有索引。

然后我有一个VB.net应用程序,基本上我希望它允许用户放置一个.txt文件与一个大量的order_nums列表(> 150,000,每行1),它做的是逐行读取这些然后搜索的数据库,将其全部添加到临时表,然后将streamwrites添加到“结果”.txt文件中。

关于这个问题的标题我问它,因为我的代码将在下面发布,有效!我正在读取时间,然后在.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

UPDATE

我已经采取了一些建议,现在我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表上放了NO索引,除了sql表外,它基本上只是.txt文件

更新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

解决所以我是最后一位的白痴,你们都是正确的,基本上当我制作临时表时,我不小心使列成为nvarchar,而在实际的OrderTable中,它只是order_num的varchar列。对不起那些家伙我半睡半醒!

sql sql-server vb.net streamreader streamwriter
4个回答
3
投票

您的代码的问题是您执行此SQL命令150k次。这永远不会起作用(快速)。

您可以做的是首先从文件中读取150k值,然后使用SqlBulkCopy插入表for example as shown in this SO answer。基本上做你的dbo.OrdersToTemp程序在你的vb.net代码中做的 - 一次完成而不是一次一行。鉴于当前查询的延迟,这应该最多花费几秒钟。

对于以下查询:

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)压缩索引,但这需要Enterprise许可证(或开发人员,但您不能在prod环境中使用它)。


1
投票

我不知道您在命令中使用的存储过程的结构,但我猜大多数情况下SQL服务器上的操作以及应用程序和SQL服务器之间的通信占用大部分时间。所以考虑那里的优化 - 比如立即将所有数字发送到程序。您不必再调用xy过程。并尝试查看存储过程的执行计划 - 有什么可以改进的吗?


1
投票

我建议进行以下优化。

首先,Bulk insert直接从txt文件进入临时订单id表。如果你在每一行都有一个order_num,那么这样做。

BULK INSERT TempOrderIdTable
FROM 'C:\data\orderids.txt'
WITH (FIRSTROW = 1,
    FIELDTERMINATOR = ',',
    ROWTERMINATOR='\n' );

要使bulk insert正常工作,SQL Server必须可以在SQL Server服务器上或通过网络上的共享位置访问该文件。

其次,通过加入临时订单ID表运行查询以一次性获取所有描述:

SELECT o.order_num, description
from OrderTable o
join TempOrderIdTable t on t.order_num = o.order_num

现在,您将分两步完成结果。


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
© www.soinside.com 2019 - 2024. All rights reserved.