Aucun message portant le libellé SQL Queries. Afficher tous les messages
Aucun message portant le libellé SQL Queries. Afficher tous les messages

SQL: documentation and scripts

J’utilise souvent les mêmes scripts pour les certaines opérations SQL. Au lieu de partager les scripts sur ce blogue, j’ai décidé de faire un billet, que je vais mettre à jour au fil du temps, qui contient la liste de tous les articles et scripts SQL que je trouve utile. 

Index et Statistics

Security
Architecture


D365 Finance and Operations: Utilisation DTU pour les base de données Azure SQL

Les environnements D365 F&O Tier 2+ utilisent Azure SQL pour les bases de données AX, Financial Reporter et Data Warehouse. Étant donnée que les environnements son hébergé par Microsoft, nous n’avons pas accès aux serveurs Azure SQL via le portail Azure. Ainsi, nous ne pouvons pas utiliser les outils de monitoring d'Azure.

Toutefois, nous pouvons utiliser l’outil Environnement Monitoring de LCS pour voir le pourcentage  d’utilisation SQL pour la base de données AxDB.


Toutefois, aucune information pour les bases de données AxDW et MrDB. Afin de savoir l’utilisation SQL pour ses deux bases de données, il faut se connecter sur le serveur Azure SQL et exécuter la requête suivante:

WITH workload_group_resource_stats_cte (end_time, avg_cpu_percent, avg_data_io_percent, avg_log_write_percent) 
AS (SELECT end_time, 
    Sum(avg_cpu_percent)       AS AVG_CPU_PERCENT, 
    Sum(avg_data_io_percent)   AS AVG_DATA_IO_PERCENT, 
    Sum(avg_log_write_percent) AS AVG_LOG_WRITE_PERCENT 
FROM   sys.dm_db_workload_group_resource_stats 
GROUP  BY end_time)
SELECT END_TIME,
 (SELECT Max(v) 
  FROM (VALUES (avg_cpu_percent), 
    (avg_data_io_percent), 
    (avg_log_write_percent)) AS VALUE(v)) AS DTU_CONSUMPTION_PERCENT,
avg_cpu_percent,avg_data_io_percent,avg_log_write_percent
FROM workload_group_resource_stats_cte
ORDER BY END_TIME DESC


SQL Server: FETCH_API consommes beaucoup de resources SQL

Lors d’une investigation d’un problème de performance avec D365 for Finance and Operations, j’ai exécuté le script Find Most Expensive Queries Using DMV de Pinal Dave et j’ai trouvé ceci:


Étant donné que le processus était toujours en cours d’exécution dans l’application, j'ai utilisé mon script qui me retourne toute les requêtes en cours d’exécution et j’ai vu le résultat ci-dessous. Il faut dire que ce fut par chance parce que comme vous pouvez le voir, c’est une petite requête qui ne consomme pas de CPU, reads, writes et logicial reads, donc elle passe vite. J’ai dû exécuter mon script plusieurs fois avant avant de la voir.


Qu’est-ce que FETCH_API ? C’est bien expliquer dans l’article suivant: Hunting down the origins of FETCH API_CURSOR and sp_cursorfetch. En résumé, le curseur est défini au début de la transaction et SQL travaille a l’intérieur de ce curseur.

Afin de voir la requête derrière le curseur, l’article mentionner plus haut propose la requête suivante (il faut remplacer le chiffre 53 par le SPID):

SELECT c.session_id, c.properties, c.creation_time, c.is_open, t.text
FROM sys.dm_exec_cursors (53) c
CROSS APPLY sys.dm_exec_sql_text (c.sql_handle) t

Celle-ci fonctionne bien si le SPID reste le même pour une longue durée. Pour ma part, j’ai fait une modification au script afin de voir tous les curseurs ouverts en ordre de worker_time, read and writes afin de facilement identifier le curseur qui consomme le plus de ressource.

SELECT c.session_id, c.properties, c.creation_time, c.is_open, t.text, worker_time, reads, writes
FROM sys.dm_exec_cursors (0) c
CROSS APPLY sys.dm_exec_sql_text (c.sql_handle) t
ORDER BY 
worker_time DESC
reads DESC
writes DESC


Voilà, je peux maintenant voir les requêtes en question.

Dynamics AX : Diagnostiquer les problèmes de verrouillage (locks) - PART 2

Il est difficile de détecter en temps réel les blocages dans une base de données. C’est pour cette raison qu’il est important de configurer SQL Extended Event. Cet outil vous permettra d’enregistrer l’historique des blocages.

Avant de configurer une session de type Extended Event, vous devez créer un dossier C:\SQLTRACE sur le serveur. Ensuite, vous pouvez exécuter la requête suivante qui vient de la solution DynamicsPerf 2.0. Celle-ci configure une session afin de collecter les requêtes bloquées pour plus de 2 secondes.

USE [master]
GO
sp_configure 'Show Advanced Options', 1
RECONFIGURE WITH OVERRIDE
GO
sp_configure 'blocked process threshold', 2
RECONFIGURE WITH OVERRIDE
GO

IF EXISTS(SELECT * FROM sys.server_event_sessions WHERE name='DYNPERF_BLOCKING_DATA')
DROP EVENT SESSION DYNPERF_BLOCKING_DATA ON SERVER
GO

CREATE EVENT SESSION [DYNPERF_BLOCKING_DATA] ON SERVER 

ADD EVENT sqlserver.blocked_process_report(
ACTION(package0.collect_system_time,sqlserver.client_hostname,sqlserver.context_info)),

ADD EVENT sqlserver.xml_deadlock_report(
ACTION(package0.collect_system_time,sqlserver.client_hostname,sqlserver.context_info)),

ADD EVENT sqlserver.lock_escalation(
ACTION(package0.collect_system_time,sqlserver.client_hostname,sqlserver.context_info)) 
ADD TARGET package0.event_file(SET filename=N'C:\SQLTrace\DYNAMICS_BLOCKING.xel',max_file_size=(10),max_rollover_files=(100))
--ADD TARGET package0.ring_buffer(SET max_memory=(131072))
WITH (MAX_MEMORY=4096 KB,MAX_DISPATCH_LATENCY=5 SECONDS,MEMORY_PARTITION_MODE=PER_NODE,TRACK_CAUSALITY=ON,STARTUP_STATE=ON)
GO

ALTER EVENT SESSION [DYNPERF_BLOCKING_DATA] ON SERVER 
STATE=START
GO



Ensuite, les événements sont collectés dans les fichiers .xel


Ensuite, vous pouvez analyser les évènements avec la requête suivante:

SELECT TOP 100 *
FROM   (SELECT event_data.value('(event/@name)[1]', 'varchar(50)')                                                                 
AS EVENT_NAME,
               DATEADD(hh, DATEDIFF(hh, GETUTCDATE(), CURRENT_TIMESTAMP), event_data.value('(/event/@timestamp)[1]', 'datetime2')) AS END_TIME,
               event_data.value('(event/data[@name="duration"]/value)[1]', 'decimal(38,3)') / 1000                                 
AS DURATION,
               event_data.value('(event/data[@name="object_id"]/value)[1]', 'int')                                                 
AS OBJECT_ID,
               event_data.value('(event/data[@name="resource_owner_type"]/value)[1]', 'varchar(max)')                              
AS RESOURCE_OWNER_TYPE,
               event_data.value('(event/data[@name="index_id"]/value)[1]', 'int')                                                  
AS INDEX_ID,
               event_data.value('(event/data[@name="lock_mode"]/value)[1]', 'varchar(max)')                                        
AS LOCK_MODE,
               event_data.value('(event/data[@name="transaction_id"]/value)[1]', 'bigint')                                            
AS TRANSACTION_ID,
               event_data.value('(event/data[@name="database_name"]/value)[1]', 'varchar(max)')                                    
AS DATABASE_NAME,
               event_data                                                                                                          
AS EVENT_DATA
        FROM   (SELECT CONVERT(XML, event_data)
                FROM   sys.fn_xe_file_target_read_file('C:\SQLTRACE\DYNAMICS_BLOCKING*.XEL', NULL, NULL, NULL)) AS evts ( event_data )) AS DYNPERF_BLOCKING
WHERE  EVENT_NAME = 'blocked_process_report'
--AND END_TIME BETWEEN  '2016-02-13 10:19:37.5520000' AND '2016-02-13 10:21:17.9560000' 
ORDER  BY END_TIME DESC



Vous pouvez cliquer sur le lien dans la colonne EVENT_DATA et pouvez y voir plusieurs informations intéressantes:
  • Blocked-process
  • Waitresource
  • Waittime
  • Lockmode
  • Status
  • Hostname
  • Isolationlevel



Dynamics AX : Diagnostiquer les problèmes de verrouillage (locks) - PART 1

Dans le passé, j’ai écrit un billet au sujet des blocs dans votre base de données SQL, aujourd'hui je voulais approfondir le sujet.

Comme nous l'avons vu, il est possible de savoir les sessions SQL bloquées. De plus, nous sommes capables d'associer la session SQL (SPID) avec la session AX lorsque connectioncontext est activé sur le serveur AOS

Aujourd’hui, je veux savoir pourquoi la session est bloquée.

Afin de faire la démonstration, je vais volontairement créer un blocage dans la base de données. Dans ma première requête, je vais mettre à jour le champ ENABLE pour le ID mathieu. Toutefois, je ne vais pas commettre la transaction immédiatement, ceci aura pour effet de verrouiller la ligne pour une durée de 30min.

(SPID 78)

BEGIN TRANSACTION
UPDATE USERINFO SET ENABLE=1 WHERE ID = 'mathieu.'
    WAITFOR DELAY '00:30:00' 
ROLLBACK TRANSACTION

Dans la seconde requête, je vais tenter de faire une modification à la même ligne:

(SPID 80)

UPDATE USERINFO SET ENABLE=0
WHERE ID = 'mathieu.'

En utilisant cette requête, je suis capable de voir que mes deux requêtes sont en cours d’exécution :

RunningQueries.sql


En utilisant la requête suivante, je peux voir que le SPID 78 bloque le SPID 80. 

QueriesWaiting.sql
Dans ce cas-ci, nous pouvons voir que le SPID 78 est bloqué à cause de la commande WAITFOR. Nous pouvons aussi voir que le SPID 80 attend après le SPID 78 afin d'acquérir un lock de type Update (LCK_M_U).


J'aimerais avoir plus d’information à ce sujet et pour ceci nous pouvons vérifier les locks dans la base de données:  

Locks.sql
Je peux voir que la session 80 attend pour obtenir un lock de type U sur la ressource (362b1400cd67). La raison est parce que la session 78 a déjà un lock de type X sur la même ressource. Un lock de type X est incompatible avec les autres lock, pour cette raison, la session 80 doit attendre. Vous pouvez lire plus au sujet des compatibilités entre lock ici: Lock Compatibility


Je vois que le type de ressource est KEY. Ceci veut dire que le lock est sur une ligne. Vous pouvez lire plus au sujet des différents types de ressource  ici: sys.dm_tran_locks (Transact-SQL). Afin de connaître la ligne, vous pouvez exécuter cette requête. 

KeyLock.sql

SELECT sys.fn_PhysLocFormatter(%%physloc%%) AS FilePageSlot, 
%%lockres%% AS LockResource, *
FROM USERINFO
WHERE %%lockres%% ='(362b1400cd67)' 

Et voilà, maintenant je sais que la session 80 attend après la session 78 afin de mettre a jour la ligne suivante:

DynamicsPerf : D'où viennent les données ?

J'aime beaucoup l'outil DynamicsPerf afin d'analyser les performances de mes environnements Dynamics AX. Toutefois, ce n'est pas un outil très user friendly. Il arrive souvent que l'outil collecte partiellement les données à l'insu du DBA ! Je vais mettre ici l'information et les requêtes TSQL qui me permettent de troubleshooter l'installation de DynamicsPerf.

DATABASES_2_COLLECT

Une requête qui me donne les bases de données à collecter

SELECT * FROM DATABASES_2_COLLECT




CAPTURE_LOG

Une requête qui me retourne les logs

SELECT * FROM CAPTURE_LOG ORDER BY STATS_TIME DESC

Une requête qui me retourne les logs qui contiennent le mot FAILED

SELECT * FROM CAPTURE_LOG
WHERE TEXT LIKE '%FAILED%'
ORDER BY STATS_TIME DESC




DYNPERF_TASK_HISTORY

Une requête qui me retourne l'historique des taches exécutées

SELECT DTS.TASK_DESCRIPTION,
                DTH.*,
                DTS.*
FROM   DYNPERF_TASK_HISTORY DTH
               INNER JOIN DYNPERF_TASK_SCHEDULER DTS
               ON DTH.TASK_ID = DTS.TASK_ID
ORDER  BY DTH.TASK_ID 


SQL JOBS

Cette requête me retourne l'information sur les SQL Jobs de Dynamics Perf

SELECT 
sJOB.name AS [Job Name],

CASE
WHEN sSCH.schedule_uid IS NULL THEN 'No'
ELSE 'Yes'
END AS [Schedule Enabled],

CASE sJOB.enabled
WHEN 1 THEN 'Yes'
WHEN 0 THEN 'No'
END AS [Job Enabled],

CASE sJSTP.last_run_outcome
WHEN 0 THEN 'Failed'
WHEN 1 THEN 'Succeeded'
WHEN 2 THEN 'Retry'
WHEN 3 THEN 'Canceled'
WHEN 5 THEN 'Unknown'
END AS [Last Run Outcome],

CASE 
WHEN [sJSTP].[last_run_date] IS NULL OR [sJSTP].[last_run_time] IS NULL OR [sJSTP].[last_run_date] = 0 OR [sJSTP].[last_run_time] = 0 THEN NULL
ELSE CAST(CAST([sJSTP].[last_run_date] AS CHAR(8)) + ' ' + STUFF(STUFF(RIGHT('000000' + CAST([sJSTP].[last_run_time] AS VARCHAR(6)),  6), 3, 0, ':'), 6, 0, ':')  AS SMALLDATETIME)
END AS [Last Run Date Time],

STUFF(STUFF(RIGHT('000000' + CAST([sJSTP].[last_run_duration] AS VARCHAR(6)),  6) , 3, 0, ':') , 6, 0, ':') AS [Last Run Duration (HH:MM:SS)],

CASE
WHEN [sJOBSCH].[next_run_date] IS NULL OR [sJOBSCH].[next_run_time] IS NULL OR [sJOBSCH].[next_run_date] = 0 OR [sJOBSCH].[next_run_time] =0  THEN NULL
ELSE CAST(CAST([sJOBSCH].[next_run_date] AS CHAR(8)) + ' ' + STUFF(STUFF(RIGHT('000000' + CAST([sJOBSCH].[next_run_time] AS VARCHAR(6)),  6), 3, 0, ':'), 6, 0, ':') AS SMALLDATETIME)
END AS [Next Run Date Time],

CASE sSCH.freq_type
WHEN 1 THEN 'One time only'
WHEN 4 THEN 'Daily'
WHEN 8 THEN 'Weekly'
WHEN 16 THEN 'Monthly'
WHEN 32 THEN 'Monthly'
WHEN 64 THEN 'Runs when the SQL Server Agent service starts'
WHEN 128 THEN 'Runs when the computer is idle'
END AS [Frequency],
 
sJOB.date_created AS [Creation Date]
FROM
msdb.dbo.sysjobs AS sJOB
LEFT JOIN msdb.dbo.syscategories AS sCAT ON sJOB.category_id = sCAT.category_id
LEFT JOIN msdb.dbo.sysjobsteps AS sJSTP ON sJOB.job_id = sJSTP.job_id AND sJOB.start_step_id = sJSTP.step_id
LEFT JOIN msdb.dbo.sysjobschedules AS sJOBSCH ON sJOB.job_id = sJOBSCH.job_id
LEFT JOIN msdb.dbo.sysschedules AS sSCH ON sJOBSCH.schedule_id = sSCH.schedule_id
WHERE sJOB.name IN ('DYNPERF_PROCESS_TASKS_LOW_PRIORITY','DYNPERF_PURGE_QUERYPLANS','DYNPERF_COLLECT_AOS_CONFIG','DYNPERF_PROCESS_TASKS','DYNPERF_CAPTURE_STATS','DYNPERF_CAPTURE_SSRS')



TABLES

Je me sers de la requête suivante pour savoir le nombre de lignes par table. Je suis ainsi capable d'identifier plus facilement les données qui manquent.

SELECT  t.NAME AS TableName,
                 p.[Rows]
FROM  sys.tables t
INNER JOIN sys.partitions p ON t.object_id = p.object_id
WHERE t.NAME NOT LIKE '%CRM%' AND index_id < 2
ORDER BY ROWS ASC, TableName ASC





Il arrive que je trouve certaines tables avec aucune donnée. Il est difficile de savoir la raison. Afin de m'aider à trouver le problème, j'ai identifié la source de données pour chaque table de DynamicsPerf. Par exemple, je sais maintenant que les données dans QUERY_STATS proviennent d'une Store procédure nommée DYNPERF_COLLECT_QUERY_STATS qui est exécutée par une SQL Job nommée DYNPERF_CAPTURE_STATS


Type
Name
Tables
Schedule
AX Batch Job
AOTExport
dbo.AX_BATCHJOB_DETAIL
dbo.AX_BATCHSERVERGROUP_CONFIG
dbo.AX_CONFIGURATIONKEY_DETAIL
dbo.AX_INDEX_DETAIL
dbo.AX_SERVER_CONFIG
dbo.AX_TABLE_DETAIL

SQL Job
DYNPERF_COLLECT_AOS_CONFIG
dbo.AOS_EVENTLOG
dbo.AOS_REGISTRY
Every day at 6AM
SQL Query
4-ConfigureDBs to Collect.sql
dbo.DATABASES_2_COLLECT
Manual
SQL Query
5-Setup SSRS Data Collection.sql
dbo.SSRS_CONFIG
Manual

SQL JOB - DYNPERF_CAPTURE_STATS
Type
Name
Tables
Schedule (default)
Store Proc
DYNPERF_COLLECT_QUERY_STATS
dbo.QUERY_STATS
Every 5 minutes
Store Proc
DYNPERF_COLLECT_INDEXSTATS
dbo.INDEX_DETAIL
Every 1 hour
Store Proc
DYNPERF_COLLECT_SQL_TEXT
dbo.QUERY_TEXT
Every 5 minutes
Store Proc
DYNPERF_COLLECT_QUERY_PLANS
dbo.QUERY_PLANS_PARSED
Every 5 minutes
Store Proc
DYNPERF_COLLECT_SYSOBJECTS
dbo.DYNSYSOBJECTS
dbo.DYNSYSCOLUMNS
dbo.DYNSYSINDEXES
dbo.DYNSYSCOLUMNS
Every 1 day
Store Proc
DYNPERF_COLLECT_WAITSTATS
dbo.WAIT_STATS
Every 1 hour
Store Proc
DYNPERF_COLLECT_VIRTIALIO_DISKSTATS
dbo.DISKSTATS
Every 1 hour
Store Proc
DYNPERF_COLLECT_CHANGE_DATA_CONTROL
dbo.CDC
Every 1 day
Store Proc
DYNPERF_COLLECT_CHANGE_TRACKING
dbo.SQL_CHANGETRACKING_DBS
dbo.SQL_CHANGETRACKING_TABLES
Every 1 day
Store Proc
DYNPERF_COLLECT_SQL_DATA_BUFFER_CACHE
dbo.BUFFER_DETAIL
Every 1 day
Store Proc
DYNPERF_COLLECT_SQL_DATABASES
dbo.SQL_DATABASES
Every 1 day
Store Proc
DYNPERF_COLLECT_DATABASE_REPLICATION_INFO
dbo.SQL_REPLICATION
Every 1 day
Store Proc
DYNPERF_COLLECT_SQL_CONFIGURATION
dbo.SQL_CONFIGURATION
Every 1 day
Store Proc
DYNPERF_COLLECT_SQL_DATABASE_FILES
dbo.SQL_DATABASEFILES
Every 1 day
Store Proc
DYNPERF_COLLECT_DATABASE_VLFS
dbo.LOGINFO
Every 1 day
Store Proc
DYNPERF_COLLECT_INDEX_USAGE_STATS
dbo.INDEX_USAGE_STATS
Every 1 hour
Store Proc
DYNPERF_COLLECT_INDEX_OPERATIONAL_STATS
dbo.INDEX_OPERATIONAL_STATS
Every 1 hour
Store Proc
DYNPERF_COLLECT_SQL_JOBS
dbo.SQL_JOBS
Every 1 day
Store Proc
DYNPERF_COLLECT_SERVERINFO
dbo.SERVERINFO
Every 1 day
Store Proc
DYNPERF_COLLECT_SERVER_REGISTRY
dbo.SERVER_REGISTRY
Every 1 day
Store Proc
DYNPERF_COLLECT_SERVER_DISKVOLUMES
dbo.SERVER_DISKVOLUMES
Every 1 week
Store Proc
DYNPERF_COLLECT_SERVER_OS_INFO
dbo.SERVER_OS_VERSION
Every 1 week
Store Proc
DYNPERF_COLLECT_TRIGGER_INFO
dbo.TRIGGER_TABLE
Every 1 day
Store Proc
DYNPERF_COLLECT_SQL_TRACEFLAGS_RUNNING
dbo.TRACEFLAGS
Every 1 day
Store Proc
DYNPERF_COLLECT_SQL_ERRORLOG
dbo.SQLERRORLOG
Every 5 minutes
Store Proc
DYNPERF_COLLECT_DATABASE_STATISTICS
dbo.INDEX_STAT_HEADER
dbo.INDEX_DENSITY_VECTOR
dbo.INDEX_HISTOGRAM
Every 1 week
Store Proc
DYNPERF_COLLECT_SQL_PLAN_GUIDES
dbo.SQL_PLAN_GUIDES
Every 1 day
Store Proc
DYNPERF_COLLECT_PERF_COUNTERS
dbo.PERF_COUNTER_DATA
Every 5 minutes
Store Proc
DYNPERF_COLLECT_PERF_COUNTERS_AZURE
dbo.PERF_COUNTER_DATA
Every 5 minutes
Store Proc
DYNPERF_COLLECT_AZURE_EVENTLOG
dbo.AZURE_EVENTS
Every 5 minutes
Store Proc
DYNPERF_COLLECT_AX_SQLTRACE
dbo.AX_SQLTRACE
Every 5 minutes
Store Proc
DYNPERF_COLLECT_AX_SQLSTORAGE
dbo.AX_SQLSTORAGE
Every 1 week
Store Proc
DYNPERF_COLLECT_AX_USERINFO
dbo.AX_USERINFO
Every 1 day
Store Proc
DYNPERF_COLLECT_AX_NUMBERSEQUENCE
dbo.AX_NUM_SEQUENCES
Every 1 hour
Store Proc
DYNPERF_COLLECT_AX_SYSGLOBALCONFIG
dbo.AX_SYSGLOBALCONFIGURATION
Every 1 day
Store Proc
DYNPERF_COLLECT_AX_USERINFO
dbo.AX_USERINFO
Every 1 day

SQL JOB - DYNPERF_CAPTURE_SSRS

Type
Name
Tables
Schedule (default)
Store Proc
DYNPERF_COLLECT_SSRS_EXECUTIONLOG
dbo.WRK_TZ_SQL_INFO
dbo.SSRS_EXECUTIONLOG
Every 5 minutes