SQL-импорт файла расширенных событий с использованием sys.fn_xe_file_target_read_file, как получить значения только после последнего импорта - PullRequest
0 голосов
/ 25 января 2019

Я использую SQL Server 2012

У меня есть длительное расширенное событие (выполняется в течение нескольких дней для захвата событий), которое сохраняется в файл .xel.

У меня есть задание, которое периодически запускается для импорта данных в промежуточную таблицу. Я импортирую только столбец XML event_data из файла, чтобы я мог разобрать нужные мне поля XML и сохранить их в таблице для отчетов.

Я знаю, когда в последний раз я запускал импорт, поэтому я хочу посмотреть, могу ли я выбрать только те записи из файла, которые были добавлены с момента последнего запуска процесса импорта.

Сейчас он работает, но он импортирует ВСЕ записи из файлов в промежуточные таблицы, анализирует нужные мне поля (включая метку времени), затем импортирует только те записи, которые имеют метку времени с момента последнего выполнения задания.

Мой процесс вставляет только новые с момента последнего запуска задания, так что все работает нормально, но выполняет большую часть работы, импортируя и анализируя XML для ВСЕХ записей в файле, включая те, которые я уже импортировал в прошлый раз работа закончилась.

Поэтому я хочу найти способ вообще не импортировать из файла, если он уже был импортирован, или, по крайней мере, не нужно анализировать XML для записей, которые уже были импортированы (хотя я должен проанализировать его сейчас, чтобы получить отметка времени для исключения уже обработанных).

Ниже приведено то, что у меня есть, и, как я уже сказал, оно работает, но выполняет много дополнительной работы, если я могу найти способ пропустить уже импортированные.

Я включил в свой процесс только те шаги, по которым мне нужна помощь:

-- pull data from file path and insert into staging table
INSERT INTO #CaptureObjectUsageFileData (event_data)
SELECT cast(event_data as XML) as event_data
FROM sys.fn_xe_file_target_read_file(@FilePathNameToImport, null, null, null)


-- parse out the data needed (only columns using) and insert into temp table for parsed data
INSERT INTO #CaptureObjectUsageEventData (EventTime, EventObjectType, EventObjectName)
SELECT n.value('(@timestamp)[1]', 'datetime') AS [utc_timestamp],
n.value('(data[@name="object_type"]/text)[1]', 'varchar(500)') AS ObjectType,
n.value('(data[@name="object_name"]/value)[1]', 'varchar(500)') as ObjectName
from (
    SELECT event_data
    FROM #CaptureObjectUsageFileData (NOLOCK)
) ed
CROSS apply ed.event_data.nodes('event') as q(n)


-- select from temp table as another step for speed/conversion
--  converting the timestamp to smalldatetime so it doesnt get miliseconds so when we select distinct it wont have lots of dupes
INSERT INTO DBALocal.dbo.DBObjectUsageTracking(DatabaseID, ObjectType, ObjectName, ObjectUsageDateTime)
SELECT DISTINCT @DBID, EventObjectType, EventObjectName, CAST(EventTime AS SMALLDATETIME)
FROM #CaptureObjectUsageEventData
WHERE EventTime > @LastRunDateTime

Ответы [ 2 ]

0 голосов
/ 25 января 2019

Принял ответ выше, но опубликовал код раздела, по которому у меня возникли вопросы, полностью с обновлениями из комментариев / исправлений, которые я сделал (опять же не весь код), но важными частями.С помощью справки @Shnugo я смог полностью удалить временную таблицу из своего процесса, которая была необходима для фильтрации даты перед вставкой в ​​постоянную таблицу, с его ответом я мог просто вставить ее непосредственно в постоянную таблицу.В моем тестировании небольших наборов данных обновление и удаление дополнительного кода сократили время выполнения на 1/3.Чем больше данных я получу, тем большее влияние окажет это улучшение.

Это предназначено для запуска сеанса расширенных событий в течение длительного периода времени.Он скажет мне, какие объекты используются (для последующего запроса к системным таблицам), чтобы сказать, какие из них НЕ используются.См. Код генерации расширенных событий ниже: я собираю информацию о: sp_statement_starting и собираю только события SP и функции и сохраняю только имя объекта, тип и метку времени. Я НЕ сохраняю текст SQL, потому что он не нужен для моих целей.

Процедура sp_statement_starting извлекает каждый оператор внутри хранимой процедуры, поэтому при запуске SP он может иметь от 1 до 100 операторов, начинающих события, и вставлять в файл столько записей (что для моих целей намного больше данных, чем необходимо).

В моем коде после импорта файла в промежуточную таблицу я сокращаю метку времени до shortdatetime и выбираю отличительные значения из всех записей в файле

Я делаю это, потому что он вставляет записьдля каждого оператора внутри SP сокращение данных до короткого времени и выбор отличного значительно сокращают количество вставляемых рекродов.

Я знаю, что могу просто сохранить имя объекта и только вставить уникальные значения и полностью игнорировать время, ноЯхочу приблизительно увидеть, как часто они называются.

CREATE EVENT SESSION [CaptureObjectUsage_SubmissionEngine] ON SERVER 
ADD EVENT sqlserver.sp_statement_starting(
    -- collect object name but NOT statement, thats not needed
    SET collect_object_name=(1),
    collect_statement=(0)
    WHERE (
    -- this is for functions or SP's
        (
            -- functions
            [object_type]=(8272) 
            -- SProcs
            OR [object_type]=(20038)
        ) 
        AND [sqlserver].[database_name]=N'DBNAMEHERE' 
        AND [sqlserver].[is_system]=(0))
    ) 
ADD TARGET package0.event_file( 
    SET filename=N'c:\Path\CaptureObjectUsage.xel'  -- mine that was default UI gave me
)
WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=OFF,STARTUP_STATE=OFF)
GO




-- ***************************************************************************
--      code for importing
-- ***************************************************************************

-- pull data from file path and insert into staging table
INSERT INTO #CaptureObjectUsageFileData (event_data)
SELECT cast(event_data as XML) as event_data
FROM sys.fn_xe_file_target_read_file(@FilePathNameToImport, null, null, null)


-- with the XML.nodes parsing I can insert directly into my final table because it does the logic here
INSERT INTO DBALocal.dbo.DBObjectUsageTracking(DatabaseID, ObjectType, ObjectName, ObjectUsageDateTime)
SELECT DISTINCT @DBID, -- @DBID is variable I set above so I dont need to use DBNAME and take up a ton more space
n.value('(data[@name="object_type"]/text)[1]', 'varchar(500)') AS ObjectType,
n.value('(data[@name="object_name"]/value)[1]', 'varchar(500)') as ObjectName,
CAST(n.value('(@timestamp)[1]', 'datetime') AS SMALLDATETIME) AS [utc_timestamp]
from (
    SELECT event_data
    FROM #CaptureObjectUsageFileData (NOLOCK)
) ed
-- original  before adding the .node logic
--CROSS apply ed.event_data.nodes('event') as q(n)
-- updated to reduce amount of data to import
CROSS apply ed.event_data.nodes('event[@timestamp cast as xs:dateTime? > sql:variable("@LastRunDateTime")]') as q(n)
0 голосов
/ 25 января 2019

Хорошо, я уже разместил комментарий, но - подумав немного глубже и изучив ваш код - это может быть довольно просто:

Вы можете сохранить время вашего последнего импорта и использовать предикат в .nodes() (как вы делаете это в .value(), чтобы получить правильный <data> -элемент).

Попробуйте что-то вроде этого:

DECLARE @LastImport DATETIME=GETDATE(); --put the last import's time here

and then

CROSS apply ed.event_data.nodes('event[@timestamp cast as xs:dateTime? > sql:variable("@LastImport")]') as q(n)

При этом .nodes() должен возвращать только <event> -элементы, где условие выполнено. Если это не помогает, пожалуйста, покажите сокращенный пример XML и что вы хотите получить.

...