好的,这就是场景......我在Oracle中有一个像队列一样的表... VB.net程序读取队列并调用SQL Server中的存储过程,该过程处理然后将消息插入另一个SQL Server表,然后从oracle表中删除该记录。
我们使用DataReader从Oracle读取记录,然后为每个记录调用存储过程。该计划似乎有点慢。存储过程本身并不慢。在循环中调用SP本身可以在20秒内处理大约2000条记录。但是当从.Net程序调用时,执行时间大约是每秒5条记录。 我已经看到消耗的大部分时间是调用存储过程并等待它返回。有没有更好的方法呢?
以下是实际代码的片段
Function StartDataXfer() As Boolean
Dim status As Boolean = False
Try
SqlConn.Open()
OraConn.Open()
c.ErrorLog(Now.ToString & "--Going to Get the messages from oracle", 1)
If GetMsgsFromOracle() Then
c.ErrorLog(Now.ToString & "--Got messages from oracle", 1)
If ProcessMessages() Then
c.ErrorLog(Now.ToString & "--Finished Processing all messages in the queue", 0)
status = True
Else
c.ErrorLog(Now.ToString & "--Failed to Process all messages in the queue", 0)
status = False
End If
Else
status = True
End If
StartDataXfer = status
Catch ex As Exception
Finally
SqlConn.Close()
OraConn.Close()
End Try
End Function
Private Function GetMsgsFromOracle() As Boolean
Try
OraDataAdapter = New OleDb.OleDbDataAdapter
OraDataTable = New System.Data.DataTable
OraSelCmd = New OleDb.OleDbCommand
GetMsgsFromOracle = False
With OraSelCmd
.CommandType = CommandType.Text
.Connection = OraConn
.CommandText = GetMsgSql
End With
OraDataAdapter.SelectCommand = OraSelCmd
OraDataAdapter.Fill(OraDataTable)
If OraDataTable.Rows.Count > 0 Then
GetMsgsFromOracle = True
End If
Catch ex As Exception
GetMsgsFromOracle = False
End Try
End Function
Private Function ProcessMessages() As Boolean
Try
ProcessMessages = False
PrepareSQLInsert()
PrepOraDel()
i = 0
Dim Method As Integer
Dim OraDataRow As DataRow
c.ErrorLog(Now.ToString & "--Going to call message sending procedure", 2)
For Each OraDataRow In OraDataTable.Rows
With OraDataRow
Method = GetMethod(.Item(0))
SQLInsCmd.Parameters("RelLifeTime").Value = c.RelLifetime
SQLInsCmd.Parameters("Param1").Value = Nothing
SQLInsCmd.Parameters("ID").Value = GenerateTransactionID() ' Nothing
SQLInsCmd.Parameters("UID").Value = Nothing
SQLInsCmd.Parameters("Param").Value = Nothing
SQLInsCmd.Parameters("Credit").Value = 0
SQLInsCmd.ExecuteNonQuery()
'check the return value
If SQLInsCmd.Parameters("ReturnValue").Value = 1 And SQLInsCmd.Parameters("OutPutParam").Value = 0 Then 'success
'delete the input record from the source table once it is logged
c.ErrorLog(Now.ToString & "--Moved record successfully", 2)
OraDataAdapter.DeleteCommand.Parameters("P(0)").Value = OraDataRow.Item(6)
OraDataAdapter.DeleteCommand.ExecuteNonQuery()
c.ErrorLog(Now.ToString & "--Deleted record successfully", 2)
OraDataAdapter.Update(OraDataTable)
c.ErrorLog(Now.ToString & "--Committed record successfully", 2)
i = i + 1
Else 'failure
c.ErrorLog(Now.ToString & "--Failed to exec: " & c.DestIns & "Status: " & SQLInsCmd.Parameters("OutPutParam").Value & " and TrackId: " & SQLInsCmd.Parameters("TrackID").Value.ToString, 0)
End If
If File.Exists("stop.txt") Then
c.ErrorLog(Now.ToString & "--Stop File Found", 1)
'ProcessMessages = True
'Exit Function
Exit For
End If
End With
Next
OraDataAdapter.Update(OraDataTable)
c.ErrorLog(Now.ToString & "--Updated Oracle Table", 1)
c.ErrorLog(Now.ToString & "--Moved " & i & " records from Oracle to SQL Table", 1)
ProcessMessages = True
Catch ex As Exception
ProcessMessages = False
c.ErrorLog(Now.ToString & "--MoveMsgsToSQL: " & ex.Message, 0)
Finally
OraDataTable.Clear()
OraDataTable.Dispose()
OraDataAdapter.Dispose()
OraDelCmd.Dispose()
OraDelCmd = Nothing
OraSelCmd = Nothing
OraDataTable = Nothing
OraDataAdapter = Nothing
End Try
End Function
Public Function GenerateTransactionID() As Int64
Dim SeqNo As Int64
Dim qry As String
Dim SqlTransCmd As New OleDb.OleDbCommand
qry = " select seqno from StoreSeqNo"
SqlTransCmd.CommandType = CommandType.Text
SqlTransCmd.Connection = SqlConn
SqlTransCmd.CommandText = qry
SeqNo = SqlTransCmd.ExecuteScalar
If SeqNo > 2147483647 Then
qry = "update StoreSeqNo set seqno=1"
SqlTransCmd.CommandText = qry
SqlTransCmd.ExecuteNonQuery()
GenerateTransactionID = 1
Else
qry = "update StoreSeqNo set seqno=" & SeqNo + 1
SqlTransCmd.CommandText = qry
SqlTransCmd.ExecuteNonQuery()
GenerateTransactionID = SeqNo
End If
End Function
Private Function PrepareSQLInsert() As Boolean
'function to prepare the insert statement for the insert into the SQL stmt using
'the sql procedure SMSProcessAndDispatch
Try
Dim dr As DataRow
SQLInsCmd = New OleDb.OleDbCommand
With SQLInsCmd
.CommandType = CommandType.StoredProcedure
.Connection = SqlConn
.CommandText = SQLInsProc
.Parameters.Add("ReturnValue", OleDb.OleDbType.Integer)
.Parameters("ReturnValue").Direction = ParameterDirection.ReturnValue
.Parameters.Add("OutPutParam", OleDb.OleDbType.Integer)
.Parameters("OutPutParam").Direction = ParameterDirection.Output
.Parameters.Add("TrackID", OleDb.OleDbType.VarChar, 70)
.Parameters.Add("RelLifeTime", OleDb.OleDbType.TinyInt)
.Parameters("RelLifeTime").Direction = ParameterDirection.Input
.Parameters.Add("Param1", OleDb.OleDbType.VarChar, 160)
.Parameters("Param1").Direction = ParameterDirection.Input
.Parameters.Add("TransID", OleDb.OleDbType.VarChar, 70)
.Parameters("TransID").Direction = ParameterDirection.Input
.Parameters.Add("UID", OleDb.OleDbType.VarChar, 20)
.Parameters("UID").Direction = ParameterDirection.Input
.Parameters.Add("Param", OleDb.OleDbType.VarChar, 160)
.Parameters("Param").Direction = ParameterDirection.Input
.Parameters.Add("CheckCredit", OleDb.OleDbType.Integer)
.Parameters("CheckCredit").Direction = ParameterDirection.Input
.Prepare()
End With
Catch ex As Exception
c.ErrorLog(Now.ToString & "--PrepareSQLInsert: " & ex.Message)
End Try
End Function
Private Function PrepOraDel() As Boolean
OraDelCmd = New OleDb.OleDbCommand
Try
PrepOraDel = False
With OraDelCmd
.CommandType = CommandType.Text
.Connection = OraConn
.CommandText = DelSrcSQL
.Parameters.Add("P(0)", OleDb.OleDbType.VarChar, 160) 'RowID
.Parameters("P(0)").Direction = ParameterDirection.Input
.Prepare()
End With
OraDataAdapter.DeleteCommand = OraDelCmd
PrepOraDel = True
Catch ex As Exception
PrepOraDel = False
End Try
End Function
我想知道的是,如果还有加速这个程序的话? 任何想法/建议都将受到高度赞赏......
Regardss, 阿赫亚
答案 0 :(得分:3)
由于Oracle和SQL Server可以参与分布式事务,为什么不编写SSIS作业来查询Oracle并运行SQL Server存储过程,删除“排队”记录等?
创建SQL Server链接服务器到Oracle数据库...
[添加@Bob Jarvis关于首次分析的评论,以确保瓶颈在您认为的位置:EqaTec .NET代码分析器是免费供个人使用...]
答案 1 :(得分:1)
如果存储过程不是问题,那么它必须与调用存储过程相关联。由于我们无法更改/修复.Net本身,让我们看看我们可以改变的事情。
调用存储过程时,您正在对StoreSeqNo表进行选择和更新(请参阅对GenerateTransactionID的调用)。这可能是减速的一部分,特别是因为你在没有WHERE子句的情况下查询StoreSeqNo。另外,我建议您了解序列,这些序列是用于生成非重复序列号的对象,可以安全地在事务,用户等之间使用。我不知道SQL Server是否支持它们(没有使用SQL Server几年了)但我确信它们在Oracle中得到了支持。
此外,还有“Method = GetMethod(.Item(0))”调用。 GetMethod是你的程序之一吗?它没有显示在代码片段中,但也许这会增加一些开销?您可能想尝试添加一些代码来确定哪些行花费的时间最多。我怀疑那里有.Net的探测器。
只是一些想法。祝你好运。