Чета то ли не приходилось это делать, то ли сделал и забыл...
Вот есть допустим Linq2Sql выражение, хочется увидеть какие SQL запросы оно отправит в базу данных.
Или есть запутанное большое приложение общающееся с базой, нужно увидеть все входящие запросы пришедшие к базе.
Напомните, как это делается?
Здравствуйте, Министр Промышленности, Вы писали:
МП>Или есть запутанное большое приложение общающееся с базой, нужно увидеть все входящие запросы пришедшие к базе.
МП>Напомните, как это делается?
Раньше был SQL Server Profiler но он вроде бы уже deprecated и не развивается и рекомендуют использовать Extended Events для этого...
Но я по старинке все еще работаю SQL Server Profiler т.к. у меня 2012-2016 сиквел серваки
Здравствуйте, Jericho113, Вы писали:
МП>>Или есть запутанное большое приложение общающееся с базой, нужно увидеть все входящие запросы пришедшие к базе.
МП>>Напомните, как это делается?
J>Раньше был SQL Server Profiler но он вроде бы уже deprecated и не развивается и рекомендуют использовать Extended Events для этого...
Это UI не развивается. А API развивается и ни разу не депрекатед:
https://docs.microsoft.com/en-us/sql/relational-databases/system-functions/sys-fn-trace-gettable-transact-sql?view=sql-server-ver15
J>Но я по старинке все еще работаю SQL Server Profiler т.к. у меня 2012-2016 сиквел серваки
J>>Раньше был SQL Server Profiler но он вроде бы уже deprecated и не развивается и рекомендуют использовать Extended Events для этого...
VC>Это UI не развивается. А API развивается и ни разу не депрекатед:
VC>https://docs.microsoft.com/en-us/sql/relational-databases/system-functions/sys-fn-trace-gettable-transact-sql?view=sql-server-ver15
По ссылке.
Important
This feature will be removed in a future version of Microsoft SQL Server. Avoid using this feature in new development work, and plan to modify applications that currently use this feature. Use Extended Events instead.
Здравствуйте, yenik, Вы писали:
Y>По ссылке.
Y>Y>Important
Y>This feature will be removed in a future version of Microsoft SQL Server. Avoid using this feature in new development work, and plan to modify applications that currently use this feature. Use Extended Events instead.
вот блин. ну и ладно. а мы по прежнему юзаем ::fn_trace_gettable вместо sys.fn_trace_gettable, она уже лет 12 депрекатед но работает в SQL 2019 хоть обычном хоть в линуксе
этоже sql сервер а не какой то там IE с macOS
кстати сиквела нового не будет, только Windows Server 2021
https://rcpmag.com/articles/2011/02/01/the-2011-microsoft-product-roadmap.aspx
Здравствуйте, Министр Промышленности, Вы писали:
МП>Чета то ли не приходилось это делать, то ли сделал и забыл...
МП>Вот есть допустим Linq2Sql выражение, хочется увидеть какие SQL запросы оно отправит в базу данных.
Неужели возникли какие-то проблемы с
https://www.google.com/search?q=Linq2Sql+log+queries?
Вообще,
Посмотреть, что для этого предлагает сам движок запросов. Например для EF Core Overview of Logging and Interception
Если это не подходит, можно Enable event tracing in SqlClient, но тут сложнее — более низкоуровневая информация, зато для всего ADO.NET.
МП>Или есть запутанное большое приложение общающееся с базой, нужно увидеть все входящие запросы пришедшие к базе.
Опять же, если интересует то, что отправило приложение, то см. выше. Если то, что пришло на сервер, то уже средствами сервера. Для сиквела SQL Server Profiler или
XEvent Profiler
МП>Напомните, как это делается?
DiagnosticSource
Вот пример, потраха замени на свои:
using System;
using System.Text;
using System.Data.SqlClient;
using Microsoft.Extensions.DiagnosticAdapter;
using System.Diagnostics;
using System.Collections.Generic;
using Microsoft.SqlServer.Server;
using System.Linq;
namespace EDW.CrewPage.Telemetry.DiagnosticListeners
{
public static class RequestTelemetryMiddlewareExtensions
{
public static IApplicationBuilder UseRequestTelemetry(
this IApplicationBuilder app,
RequestTelemetryMiddlewareOptions options)
{
DiagnosticListener.AllListeners.Subscribe(new SqlClientListener());
}
}
public class SqlClientListener : IObserver<DiagnosticListener>
{
private readonly List<IDisposable> _subscriptions;
public SqlClientListener()
{
_subscriptions = new List<IDisposable>();
}
void IObserver<DiagnosticListener>.OnNext(DiagnosticListener diagnosticListener)
{
if (diagnosticListener.Name == "SqlClientDiagnosticListener")
{
var subscription = diagnosticListener.SubscribeWithAdapter(this);
_subscriptions.Add(subscription);
}
}
void IObserver<DiagnosticListener>.OnError(Exception error)
{ }
void IObserver<DiagnosticListener>.OnCompleted()
{
_subscriptions.ForEach(x => x.Dispose());
_subscriptions.Clear();
}
private string FormatSqlValue(object value)
{
switch (value)
{
case string s:
return $"'{value}'";
case Guid g:
return $"'{value}'";
case DateTime d:
return $"'{d:s}'";
case bool b:
return b ? "1" : "0";
case DBNull n:
return "NULL";
default:
return value.ToString();
}
}
[DiagnosticName("System.Data.SqlClient.WriteCommand")]
public void IsEnabled1()
{
// FAKE event handler needed to make Start/Stop event handlers working
}
[DiagnosticName("System.Data.SqlClient")]
public void IsEnabled2()
{
// FAKE event handler needed to make Start/Stop event handlers working
}
private string GenerateCommandParametersSql(SqlCommand sqlCommand)
{
var parameters = new SqlParameter[sqlCommand.Parameters.Count];
sqlCommand.Parameters.CopyTo(parameters, 0);
var sb = new StringBuilder();
foreach (var sqlParameter in parameters)
{
if (sqlParameter.SqlDbType == System.Data.SqlDbType.Structured)
{
var sqlType = sqlParameter.TypeName;
sb.Append($"DECLARE {sqlParameter.ParameterName} {sqlType}\r\n\r\n");
sb.Append($"INSERT INTO {sqlParameter.ParameterName} VALUES\r\n");
sb.Append(
string.Join(",\r\n",
((IEnumerable<SqlDataRecord>)sqlParameter.Value)
.Select(x => $"({FormatSqlValue(x.GetValue(0))})")));
sb.Append("\r\n");
}
else
{
var sqlType = sqlParameter.SqlDbType + (sqlParameter.Size > 0 && sqlParameter.SqlDbType != System.Data.SqlDbType.TinyInt ? $"({sqlParameter.Size})" : "");
var sqlValue = FormatSqlValue(sqlParameter.Value);
sb.Append($"DECLARE {sqlParameter.ParameterName} {sqlType} = {sqlValue};\r\n");
}
}
return sb.ToString();
}
private void OnCommandFinished(
SqlCommand sqlCommand,
Dictionary<object, object> statistics,
Exception e)
{
if (sqlCommand == null)
{
return;
}
// Read time when command started
var startTimeMs = TelemetryManager.GetTimelineItemTimeMark(sqlCommand);
var endTimeMs = TelemetryManager.GetElapsedSinceOperationStarted();
// Save time when command finished to use it later on possible reader dispose event
TelemetryManager.SetTimelineItemTimeMark(sqlCommand);
TelemetryManager.IncreaseSqlOperationsCounter();
TelemetryManager.IncreaseSqlProcessingCounter(endTimeMs - startTimeMs);
var exec = sqlCommand.CommandType == System.Data.CommandType.StoredProcedure ? "EXEC " : string.Empty;
TelemetryManager.AddTimelineItem(
new TimelineItem
{
OperationName = exec + sqlCommand.CommandText,
OperationParameters = GenerateCommandParametersSql(sqlCommand),
StartTimeMs = startTimeMs,
EndTimeMs = endTimeMs,
IsException = e != null,
CssColor = e != null ? "red" : TelemetryConstants.SqlRequestCssColor
});
}
[DiagnosticName("System.Data.SqlClient.WriteCommandBefore")]
public void OnWriteCommandBefore(
Guid operationId,
string operation,
Guid connectionId,
SqlCommand command)
{
command.Connection.StatisticsEnabled = true;
command.Connection.ResetStatistics();
TelemetryManager.SetTimelineItemTimeMark(command);
}
[DiagnosticName("System.Data.SqlClient.WriteCommandAfter")]
public void OnCommandExecuted(
Guid operationId,
string operation,
Guid connectionId,
SqlCommand command,
Dictionary<object, object> statistics)
{
// TODO: OnCommandExecuted also could receive sql statistics so we could read it and aggregate/return per operation
// TODO: Like number of rows read, number of bytes, etc...
OnCommandFinished(command, statistics, null);
}
[DiagnosticName("System.Data.SqlClient.WriteCommandError")]
public void OnCommandError(
Guid operationId,
string operation,
Guid connectionId,
SqlCommand command,
Exception exception,
Dictionary<object, object> statistics)
{
OnCommandFinished(command, statistics, exception);
}
}
}