处理大型 .xel 文件(SQL Server 扩展事件日志)的正确工具是什么?

Raz*_*anu 8 sql-server ssms extended-events

我的目标是审计一个实例上的所有查询,谁在运行它们,从哪里运行,读取多少,以便在另一个实例上整合/迁移。

找出最好的方法是通过扩展事件到 .xel 文件,超过 2 周,复制这些文件并在我规格齐全的桌面上进行分析。用最少的细节(字段)设置捕获,所以真的不能让它更小 - 12 个文件中大约 12GB。在 SSMS 中使用“合并扩展事件文件”加载 .xel 文件并按照https://docs.microsoft.com/en-us/sql/relational-databases/extended-events/advanced-viewing-of- 中的详细说明进行处理target-data-from-extended-events-in-sql-server?view=sql-server-2017

这真的是最好的方法吗?有没有更好的工具来加载文件?使用 SSMS 17.7真的很- 例如:到目前为止(在进入分组和聚合之前)只有 4 个过滤器,它花了 12 个小时来处理 50% 的日志。

Dan*_*man 8

对于大型 XE 跟踪文件,我将自定义工具与QueryableXEventData 结合使用。我发现这比 T-SQL 中的 XML 解析要快得多。

下面是一个基本的 PowerShell,它将rpc_completed事件跟踪中的选定字段和操作以 10K 批次的形式导入到表中。您需要Add-TypeMicrosoft.SqlServer.XE.Core.dllMicrosoft.SqlServer.XEvent.Linq.dll程序集包含一个命令,该命令将位于您的 SQL Server 安装文件夹中,确切位置将因 SQL 版本和所选安装位置而异。

$SharedPath = "C:\Program Files\Microsoft SQL Server\140\Shared";
$SqlInstanceName = "";

$xeCore = [System.IO.Path]::Combine($SharedPath, "Microsoft.SqlServer.XE.Core.dll");
$xeLinq = [System.IO.Path]::Combine($SharedPath, "Microsoft.SqlServer.XEvent.Linq.dll");
Add-Type -Path $xeLinq;

if( [System.IO.File]::Exists($xeCore) )
{
    Add-Type -Path $xeCore;
}
Run Code Online (Sandbox Code Playgroud)

请注意,类中有单独的 Fields 和 Actions 集合,PublishedEvent因此您需要从适当的连接中提取值。

# create target table
$connectionString = "Data Source=.;Initial Catalog=tempdb;Integrated Security=SSPI"
$connection = New-Object System.Data.SqlClient.SqlConnection($connectionString)
$command = New-Object System.Data.SqlClient.SqlCommand(@"
CREATE TABLE dbo.rpc_completed(
      event_name sysname
    , timestamp datetimeoffset
    , statement nvarchar(MAX)
    , username nvarchar(256)
);
"@, $connection)
$connection.Open()
[void]$command.ExecuteNonQuery()
$connection.Close()

# data table for SqlBulkCopy
$dt = New-Object System.Data.DataTable
[void]$dt.Columns.Add("event_name", [System.Type]::GetType("System.String"))
$dt.Columns["event_name"].MaxLength = 256
[void]$dt.Columns.Add("timestamp", [System.Type]::GetType("System.DateTimeOffset"))
[void]$dt.Columns.Add("statement", [System.Type]::GetType("System.String"))
[void]$dt.Columns.Add("username", [System.Type]::GetType("System.String"))
$dt.Columns["username"].MaxLength = 128
$dt.Columns["statement"].MaxLength = -1

$events = new-object Microsoft.SqlServer.XEvent.Linq.QueryableXEventData("D:\TraceFiles\Log\rpc_completed*.xel")

# import XE events from file(s)
$bcp = New-Object System.Data.SqlClient.SqlBulkCopy($connectionString)
$bcp.DestinationTableName = "dbo.rpc_completed"
$eventCount = 0
foreach($event in $events) {
    $eventCount += 1
    $row = $dt.NewRow()
    $dt.Rows.Add($row)
    $row["event_name"] = $event.Name
    $row["timestamp"] = $event.Timestamp
    $row["statement"] = $event.Fields["statement"].Value
    # username is a collected action
    $row["username"] = $event.Actions["username"].Value
    if($eventCount % 10000 -eq 0) {
        $bcp.WriteToServer($dt)
        $dt.Rows.Clear()
    }
}
$bcp.WriteToServer($dt) # write last batch
Write-Host "$eventCount records imported"
Run Code Online (Sandbox Code Playgroud)