2013-06-25 50 views
2

我正尝试从PowerShell脚本中的xp_readerrorlog扩展存储过程中读取第一行。从存储过程的结果集中读取第一行

不幸的是,ExecuteReader()方法读取xp_readerrorlog存储过程返回的所有记录,有时候这是几百万行或几分钟。

我试图谷歌它,发现使用DAO可以读取数据,因为它返回的SQL Server但DAO已弃用,我不想走这条路线。

BeginExecuteReader()似乎没有帮助,因为没有迹象表明是否有任何数据已经返回,直到执行完成,等于ExecuteReader()。 在处理大型记录集时,是否有其他方法可以获取仅第几行/页?

据我所知,我可以创建一个临时表,将数据转储到它并从它SELECT TOP 1,但这会引入一些额外的I/O,这不是我正在寻找的解决方案。

+0

如何[归档](http://blogs.msdn.com/b/chrissk/archive/2011/01/05/how-to-archive-your-sql-errorlogs-into-a- table.aspx)你的错误日志并定期循环它?然后'sp/xp_readerrorlog'应该更易于管理。 –

+0

这是此特定存储过程的解决方法之一。如果没有其他解决方案,我可能会采用这种方法。但是,一般来说,我很高兴看到我问的是否可能。 – Sheva

回答

0

以.Net 4.5开头SqlCommand类有ExecuteReaderAsync()方法和SqlDataReader类有ReadAsync()方法。只要SQL Server开始使用这些新方法将数据发送到客户端,就可以开始处理数据。

不幸的是,在PowerShell中没有await运算符,所以代码看起来并不像在C#中那么漂亮。

$sqlInstance = 'SqlServerName'; 

$con = New-Object System.Data.SqlClient.SQLConnection; 
$con.ConnectionString = "Data Source=$($sqlInstance);Integrated Security=SSPI;Asynchronous Processing=true;"; 
$con.Open(); 

$cmd = New-Object System.Data.SqlClient.SQLCommand; 
$cmd.Connection = $con; 

$cmd.CommandType = [System.Data.CommandType]::StoredProcedure; 
$cmd.CommandText = 'xp_readerrorlog'; 

# add parameters 
$cmd.Parameters.Add('p1', [System.Data.SqlDbType]::Int, 1) | out-null; 
$cmd.Parameters['p1'].Value = 1; 
$cmd.Parameters.Add('p2', [System.Data.SqlDbType]::Int, 1) | out-null; 
$cmd.Parameters['p2'].Value = 1; 

$cmd.Prepare(); 

$task = $cmd.ExecuteReaderAsync(); 

# wait for first rows 
While ($task.IsCompleted -ne $true) { 
    Start-Sleep -m 10; 
} 

# PowerShell does not have await operator so a SqlDataReader object can be retrieved this way 
$reader = $task.GetAwaiter().GetResult(); 

# read first row 
$reader.ReadAsync().GetAwaiter().GetResult() | out-null; 

$reader['LogDate']; 

$cmd.Cancel(); # cancel execution, there is no need to wait for the whole recordset to be transfered to the client 

$con.Close(); 
0

我想你对Execute methods work on a ServerConnection有一个小小的误解。它们不会影响存储过程的运行方式。即使您使用了ExecuteScalar(执行Transact-SQL语句并将第一行的第一列作为值类型返回),那么整个存储过程将在服务器上运行,那么只会返回第一个值。

只有两个可以提高性能的选项是创建一个新过程,它返回所需的行(Sql性能改进和网络利用率改进)或使用临时表从存储过程返回单个行网络利用率提高)。

ServerConnection中没有内置的方法可以在.Net Framework中执行所需的操作。

+0

我没有尝试使用** SET ROWCOUNT **为 'INSERT INTO EXEC xp_readerrorlog ...' 但它实际上工作。当您直接执行存储过程时它不起作用。 这是我要使用的代码。谢谢! CREATE TABLE #errorlog( \t [LOGDATE] [DATETIME] NOT NULL, \t [ProcessInfo] [VARCHAR(20)NOT NULL, \t [文本] [文本] NOT NULL ) SET ROWCOUNT 1 INSERT INTO #errorlog EXEC xp_readerrorlog 0,1,NULL,NULL,NULL,NULL,N'desc” SELECT * FROM #errorlog DROP TABLE #errorlog – Sheva

+0

与您的评论创建您自己的答案,并接受它作为你的问题的答案。 –

+0

我刚刚在一个大的错误日志上测试了上面的代码,执行时间约为2分钟。这意味着它实际上处理完整的记录集,因此会在服务器上增加一些额外的负载。 – Sheva

相关问题