Technical audit scripts
- Get information about the system
- Review database status
- Database monitoring
- Database changes
- Helper AX jobs
- Performance hints
CREATE TABLE #Results(
[Name] nvarchar(128),
[Rows] char(11),
ReservedKB varchar(18),
DataKB varchar(18),
Index_sizeKB varchar(18),
UnusedKB varchar(18))
GO
INSERT INTO #Results
exec sp_msforeachtable @command1 = N'exec sp_spaceused ''?'', false'
SELECT [Name], [rows], REPLACE(ReservedKB, ' KB', '') as ReservedKB, REPLACE(DataKB, ' KB', '') as DataKB,
REPLACE(Index_sizeKB, ' KB', '') as Index_sizeKB, REPLACE(UnusedKB, ' KB', '') as UnusedKB FROM #Results
ORDER BY [NAME]
GO
DROP TABLE #Results
GO
--for Azure SQL
select o.name, max(s.row_count) AS 'Rows',
sum(s.reserved_page_count) * 8.0 / (1024 * 1024) as 'GB',
(8 * 1024 * sum(s.reserved_page_count)) / (max(s.row_count)) as 'Bytes/Row'
from sys.dm_db_partition_stats s, sys.objects o
where o.object_id = s.object_id
group by o.name
having max(s.row_count) > 0
order by GB desc- Version of AX and SQL
- How much memory is left on SQL Server
- Batch jobs and their time of execution
- Pending WF status
- Number of Financial dimension sets
select name, is_read_committed_snapshot_on from sys.databases
alter database Dynamics set read_committed_snapshot onDECLARE @m int
set @m = DATEDIFF(mi,SYSUTCDATETIME(), SYSDATETIME())
SELECT [STATUS]
,[FINISHING]
,[CAPTION]
,[BATCHJOBID]
,DATEADD(minute, @m, [STARTDATETIME]) as [STARTDATETIME]
,DATEADD(minute, @m, [ENDDATETIME]) as [ENDDATETIME]
,DATEDIFF(mi, STARTDATETIME, enddatetime) as [DurationMi]
,[COMPANY]
,[ALERTSPROCESSED]
,[BATCHCREATEDBY]
,[CANCELEDBY]
FROM [dbo].[BATCHJOBHISTORY]
where DATEDIFF(mi, STARTDATETIME, enddatetime) > 30 and STARTDATETIME > CONVERT(datetime, '2019-08-01', 120)
--order by STARTDATETIME desc
order by CAPTION desc
--Active users by hour
DECLARE @mOffset int
set @mOffset = DATEDIFF(mi,SYSUTCDATETIME(), SYSDATETIME())
SET DATEFORMAT YMD
DECLARE @hrs TABLE (HH INT NOT NULL)
DECLARE @DateFrom date = DATEADD(dd, -7, SYSDATETIME()), @DateTo date = SYSDATETIME()
INSERT INTO @hrs
SELECT TOP 24 ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM sys.objects
SELECT HH AS Hour
,avg(UserCnt) AS [Avg users]
,max(UserCnt) AS [Max users]
FROM (
SELECT DATE
,HH
,count(*) AS UserCnt
FROM (
SELECT DISTINCT USERID, CAST(DATEADD(mi, @mOffset, CREATEDDATETIME) AS DATE) AS DATE
,HH
FROM SYSUSERLOG
CROSS JOIN @hrs
WHERE CAST(DATEADD(mi, @mOffset, CREATEDDATETIME) AS DATE) = CAST(DATEADD(mi, @mOffset, LOGOUTDATETIME) AS DATE)
AND DATEPART(hour, DATEADD(mi, @mOffset, CREATEDDATETIME)) <= HH
AND DATEPART(hour, DATEADD(mi, @mOffset, LOGOUTDATETIME)) >= HH
AND CLIENTTYPE = 1
) T
WHERE DATE BETWEEN @DateFrom AND @DateTo
GROUP BY DATE
,HH
) TT
GROUP BY HH
ORDER BY HHSELECT [sJOB].[name] AS [JobName]
,CASE [sJOBH].[run_status] WHEN 0 THEN 'Failed' WHEN 1 THEN 'Succeeded' WHEN 2 THEN 'Retry' WHEN 3 THEN 'Canceled' WHEN 4 THEN 'Running' -- In Progress
END AS [LastRunStatus]
,STUFF(STUFF(RIGHT('000000' + CAST([sJOBH].[run_duration] AS VARCHAR(6)), 6), 3, 0, ':'), 6, 0, ':') AS [LastRunDuration (HH:MM:SS)]
,CASE WHEN [sJOBH].[run_date] IS NULL
OR [sJOBH].[run_time] IS NULL THEN NULL ELSE CAST(CAST([sJOBH].[run_date] AS CHAR(8)) + ' ' + STUFF(STUFF(RIGHT('000000' + CAST([sJOBH].[run_time] AS VARCHAR(6)), 6), 3, 0, ':'), 6, 0, ':') AS DATETIME) END AS [LastRunDateTime]
,[sJOBH].[message] AS [LastRunStatusMessage]
,CASE [freq_type] WHEN 4 THEN 'Occurs every ' + CAST([freq_interval] AS VARCHAR(3)) + ' day(s)' WHEN 8 THEN 'Occurs every ' + CAST([freq_recurrence_factor] AS VARCHAR(3)) + ' week(s) on ' + CASE WHEN [freq_interval] & 1 = 1 THEN 'Sunday' ELSE '' END + CASE WHEN [freq_interval] & 2 = 2 THEN ', Monday' ELSE '' END + CASE WHEN [freq_interval] & 4 = 4 THEN ', Tuesday' ELSE '' END + CASE WHEN [freq_interval] & 8 = 8 THEN ', Wednesday' ELSE '' END + CASE WHEN [freq_interval] & 16 = 16 THEN ', Thursday' ELSE '' END + CASE WHEN [freq_interval] & 32 = 32 THEN ', Friday' ELSE '' END + CASE WHEN [freq_interval] & 64 = 64 THEN ', Saturday' ELSE '' END WHEN 16 THEN 'Occurs on Day ' + CAST([freq_interval] AS VARCHAR(3)) + ' of every ' + CAST([freq_recurrence_factor] AS VARCHAR(3)) + ' month(s)' WHEN 32 THEN 'Occurs on ' + CASE [freq_relative_interval] WHEN 1 THEN 'First' WHEN 2 THEN 'Second' WHEN 4 THEN 'Third' WHEN 8 THEN 'Fourth' WHEN 16 THEN 'Last' END + ' ' + CASE [freq_interval] WHEN 1 THEN 'Sunday' WHEN 2 THEN 'Monday' WHEN 3 THEN 'Tuesday' WHEN 4 THEN 'Wednesday' WHEN 5 THEN 'Thursday' WHEN 6 THEN 'Friday' WHEN 7 THEN 'Saturday' WHEN 8 THEN 'Day' WHEN 9 THEN 'Weekday' WHEN 10 THEN
'Weekend day' END + ' of every ' + CAST([freq_recurrence_factor] AS VARCHAR(3)) + ' month(s)' END AS [Recurrence]
,CASE [freq_subday_type] WHEN 1 THEN 'Occurs once at ' + STUFF(STUFF(RIGHT('000000' + CAST([active_start_time] AS VARCHAR(6)), 6), 3, 0, ':'), 6, 0, ':') WHEN 2 THEN 'Occurs every ' + CAST([freq_subday_interval] AS VARCHAR(3)) + ' Second(s) between ' + STUFF(STUFF(RIGHT('000000' + CAST([active_start_time] AS VARCHAR(6)), 6), 3, 0, ':'), 6, 0, ':') + ' & ' + STUFF(STUFF(RIGHT('000000' + CAST([active_end_time] AS VARCHAR(6)), 6), 3, 0, ':'), 6, 0, ':') WHEN 4 THEN 'Occurs every ' + CAST([freq_subday_interval] AS VARCHAR(3)) + ' Minute(s) between ' + STUFF(STUFF(RIGHT('000000' + CAST([active_start_time] AS VARCHAR(6)), 6), 3, 0, ':'), 6, 0, ':') + ' & ' + STUFF(STUFF(RIGHT('000000' + CAST([active_end_time] AS VARCHAR(6)), 6), 3, 0, ':'), 6, 0, ':') WHEN 8 THEN 'Occurs every ' + CAST([freq_subday_interval] AS VARCHAR(3)) + ' Hour(s) between ' + STUFF(STUFF(RIGHT('000000' + CAST([active_start_time] AS VARCHAR(6)), 6), 3, 0, ':'), 6, 0, ':') + ' & ' + STUFF(STUFF(RIGHT('000000' + CAST([active_end_time] AS VARCHAR(6)), 6), 3, 0, ':'), 6, 0, ':') END [Frequency]
FROM [msdb].[dbo].[sysjobs] AS [sJOB]
LEFT JOIN (
SELECT [job_id]
,[run_date]
,[run_time]
,[run_status]
,[run_duration]
,[message]
,ROW_NUMBER() OVER (
PARTITION BY [job_id] ORDER BY [run_date] DESC
,[run_time] DESC
) AS RowNumber
FROM [msdb].[dbo].[sysjobhistory]
WHERE [step_id] = 0
) AS [sJOBH] ON [sJOB].[job_id] = [sJOBH].[job_id]
AND [sJOBH].[RowNumber] = 1
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].[enabled] = 1
ORDER BY [JobName]
-- all Jobs
SELECT [sJOB].[name] AS [JobName]
,CASE WHEN [run_date] IS NULL
OR [run_time] IS NULL THEN NULL ELSE CAST(CAST([run_date] AS CHAR(8)) + ' ' + STUFF(STUFF(RIGHT('000000' + CAST([run_time] AS VARCHAR(6)), 6), 3, 0, ':'), 6, 0, ':') AS DATETIME) END AS [LastRunDateTime],
STUFF(STUFF(RIGHT('000000' + CAST([run_duration] AS VARCHAR(6)), 6), 3, 0, ':'), 6, 0, ':') AS [LastRunDuration (HH:MM:SS)]
,[run_status] ,[run_duration] ,[message]
,ROW_NUMBER() OVER (
PARTITION BY [sJOBH].[job_id] ORDER BY [run_date] DESC
,[run_time] DESC ) AS RowNumber
FROM [msdb].[dbo].[sysjobhistory] [sJOBH] , [msdb].[dbo].[sysjobs] AS [sJOB]
WHERE [sJOB].[job_id] = [sJOBH].[job_id] AND [step_id] = 0
and run_duration > 600
ORDER BY [run_date] desc, [run_time] descselect count(*) as number, DatePhysical, dataareaid from inventtrans (nolock)
group by DatePhysical, dataareaid
order by number desc
select count(*) as number, Closed,dataareaid from InventSum (nolock)
Group by Closed, dataareaid
select count(*) as number, CreatedDate from SALESLINE (nolock)
group by CreatedDate
order by number desc
select USERID from SYSUSERLOG
where LOGOUTDATETIME > CONVERT(datetime, '2020-04-10', 120)
group by USERID
select COUNT(*) as RecordCount , TABLE_ ,
CASE
WHEN a.LOGTYPE = 0 THEN 'Insert'
WHEN a.LOGTYPE = 1 THEN 'Delete'
WHEN a.LOGTYPE = 2 THEN 'Update'
END as LogType,
b.name from SYSDATABASELOG a, SQLDICTIONARY b
where b.tableid = a.table_ and b.FIELDID = 0
group by a.TABLE_, b.name, a.LOGTYPE
ORDER BY RecordCount DESC
--Records count by hour
DECLARE @mOffset int
set @mOffset = DATEDIFF(mi,SYSUTCDATETIME(), SYSDATETIME())
select count(*) as 'Records count',
CONVERT(date, DATEADD(mi, @mOffset, CREATEDDATETIME)) as 'Date', DATEPART(HOUR, DATEADD(mi, @mOffset, CREATEDDATETIME)) as 'Hour' from SalesTable
where DATEADD(mi, @mOffset, CREATEDDATETIME) >= '2020-09-15'
group by CONVERT(date, DATEADD(mi, @mOffset, CREATEDDATETIME)),
DATEPART(HOUR, DATEADD(mi, @mOffset, CREATEDDATETIME))
ORDER BY
CONVERT(date, DATEADD(mi, @mOffset, CREATEDDATETIME)),
DATEPART(HOUR, DATEADD(mi, @mOffset, CREATEDDATETIME))
--Is margin alert enabled(can affect SO performance)
select DATAAREAID from SALESPARAMETERS where MCREnableMarginAlert <> 0
--Mixed statuses for WMS locations check
select * from WHSLocationProfile where AllowMixedStatus = 0 or ALLOWMIXEDBATCHES = 0 or ALLOWMIXEDITEMS = 0
--Check the number of client sessions
select * from SYSCLIENTSESSIONShttps://github.com/BrentOzarULTD/SQL-Server-First-Responder-Kit
declare @dbid int;
declare @objectid int;
set @dbid = DB_ID();
set @objectid = OBJECT_ID(N'dbo.InventTrans')
SELECT a.index_id, name, avg_fragmentation_in_percent
FROM sys.dm_db_index_physical_stats(
@dbid,
@objectid,NULL, NULL , NULL ) AS a
JOIN sys.indexes AS b ON a.object_id = b.object_id AND a.index_id = b.index_id;SELECT object_name(d.object_id, d.database_id) as tabname, DB_NAME(database_id) AS DatabaseName, equality_columns, inequality_columns, avg_user_impact, included_columns,
unique_compiles, user_seeks, user_scans, last_user_seek, last_user_scan
,p.rows AS [Table Rows]
FROM sys.dm_db_missing_index_details d
INNER JOIN sys.dm_db_missing_index_groups g
ON d.index_handle = g.index_handle
INNER JOIN sys.dm_db_missing_index_group_stats s
ON g.index_group_handle = s.group_handle
CROSS APPLY (SELECT TOP 1 rows from sys.partitions WITH (NOLOCK) WHERE sys.partitions.[object_id] = d.[object_id]) AS p
WHERE database_id = db_id()
ORDER BY avg_total_user_cost * avg_user_impact *(user_seeks + user_scans) DESCselect object_name(us.[object_id]) as Table_Name, ix.name as Index_name, ix.type_desc, user_seeks, user_scans, user_lookups, user_updates
from sys.dm_db_index_usage_stats us
inner join sys.indexes ix on ix.[object_id] = us.[object_id] and ix.index_id = us.index_id
where us.database_id = db_id() and ix.type_desc <> 'HEAP' and
(us.user_seeks + us.user_scans + us.user_lookups) = 0 and us.user_updates <>0
order by 7 descUSE master
GO
SELECT TOP 10 DB_NAME(saf.dbid) AS [Database]
, saf.name AS [Name]
, vfs.BytesRead/1048576 AS [Read (MB)]
, vfs.BytesWritten/1048576 AS [Write (MB)]
, saf.filename AS [File]
FROM sysaltfiles AS saf
JOIN ::fn_virtualfilestats(NULL,NULL) AS vfs
ON vfs.dbid = saf.dbid
AND vfs.fileid = saf.fileid
AND saf.dbid NOT IN (1,3,4)
ORDER BY vfs.BytesRead/1048576 + BytesWritten/1048576 DESC
GO
SELECT SUBSTRING(saf.physical_name, 1, 1) AS [Disk]
, SUM(vfs.num_of_bytes_read/1048576) AS [Read (MB)]
, SUM(vfs.num_of_bytes_written/1048576) AS [Write (MB)]
FROM sys.master_files AS saf
JOIN sys.dm_io_virtual_file_stats(NULL,NULL) AS vfs
ON vfs.database_id = saf.database_id
AND vfs.file_id = saf.file_id
AND saf.database_id NOT IN (1,3,4)
AND saf.type < 2
GROUP BY SUBSTRING(saf.physical_name, 1, 1)
ORDER BY [Disk]
GOWITH [Waits]
AS (SELECT wait_type, wait_time_ms/ 1000.0 AS [WaitS],
(wait_time_ms - signal_wait_time_ms) / 1000.0 AS [ResourceS],
signal_wait_time_ms / 1000.0 AS [SignalS],
waiting_tasks_count AS [WaitCount],
100.0 * wait_time_ms / SUM (wait_time_ms) OVER() AS [Percentage],
ROW_NUMBER() OVER(ORDER BY wait_time_ms DESC) AS [RowNum]
FROM sys.dm_os_wait_stats WITH (NOLOCK)
WHERE [wait_type] NOT IN (
N'BROKER_EVENTHANDLER', N'BROKER_RECEIVE_WAITFOR', N'BROKER_TASK_STOP',
N'BROKER_TO_FLUSH', N'BROKER_TRANSMITTER', N'CHECKPOINT_QUEUE',
N'CHKPT', N'CLR_AUTO_EVENT', N'CLR_MANUAL_EVENT', N'CLR_SEMAPHORE',
N'DBMIRROR_DBM_EVENT', N'DBMIRROR_EVENTS_QUEUE', N'DBMIRROR_WORKER_QUEUE',
N'DBMIRRORING_CMD', N'DIRTY_PAGE_POLL', N'DISPATCHER_QUEUE_SEMAPHORE',
N'EXECSYNC', N'FSAGENT', N'FT_IFTS_SCHEDULER_IDLE_WAIT', N'FT_IFTSHC_MUTEX',
N'HADR_CLUSAPI_CALL', N'HADR_FILESTREAM_IOMGR_IOCOMPLETION', N'HADR_LOGCAPTURE_WAIT',
N'HADR_NOTIFICATION_DEQUEUE', N'HADR_TIMER_TASK', N'HADR_WORK_QUEUE',
N'KSOURCE_WAKEUP', N'LAZYWRITER_SLEEP', N'LOGMGR_QUEUE',
N'MEMORY_ALLOCATION_EXT', N'ONDEMAND_TASK_QUEUE',
N'PARALLEL_REDO_DRAIN_WORKER', N'PARALLEL_REDO_LOG_CACHE', N'PARALLEL_REDO_TRAN_LIST',
N'PARALLEL_REDO_WORKER_SYNC', N'PARALLEL_REDO_WORKER_WAIT_WORK',
N'PREEMPTIVE_HADR_LEASE_MECHANISM', N'PREEMPTIVE_SP_SERVER_DIAGNOSTICS',
N'PREEMPTIVE_OS_LIBRARYOPS', N'PREEMPTIVE_OS_COMOPS', N'PREEMPTIVE_OS_CRYPTOPS',
N'PREEMPTIVE_OS_PIPEOPS', N'PREEMPTIVE_OS_AUTHENTICATIONOPS',
N'PREEMPTIVE_OS_GENERICOPS', N'PREEMPTIVE_OS_VERIFYTRUST',
N'PREEMPTIVE_OS_FILEOPS', N'PREEMPTIVE_OS_DEVICEOPS', N'PREEMPTIVE_OS_QUERYREGISTRY',
N'PREEMPTIVE_OS_WRITEFILE',
N'PREEMPTIVE_XE_CALLBACKEXECUTE', N'PREEMPTIVE_XE_DISPATCHER',
N'PREEMPTIVE_XE_GETTARGETSTATE', N'PREEMPTIVE_XE_SESSIONCOMMIT',
N'PREEMPTIVE_XE_TARGETINIT', N'PREEMPTIVE_XE_TARGETFINALIZE',
N'PWAIT_ALL_COMPONENTS_INITIALIZED', N'PWAIT_DIRECTLOGCONSUMER_GETNEXT',
N'QDS_PERSIST_TASK_MAIN_LOOP_SLEEP',
N'QDS_ASYNC_QUEUE',
N'QDS_CLEANUP_STALE_QUERIES_TASK_MAIN_LOOP_SLEEP', N'REQUEST_FOR_DEADLOCK_SEARCH',
N'RESOURCE_QUEUE', N'SERVER_IDLE_CHECK', N'SLEEP_BPOOL_FLUSH', N'SLEEP_DBSTARTUP',
N'SLEEP_DCOMSTARTUP', N'SLEEP_MASTERDBREADY', N'SLEEP_MASTERMDREADY',
N'SLEEP_MASTERUPGRADED', N'SLEEP_MSDBSTARTUP', N'SLEEP_SYSTEMTASK', N'SLEEP_TASK',
N'SLEEP_TEMPDBSTARTUP', N'SNI_HTTP_ACCEPT', N'SP_SERVER_DIAGNOSTICS_SLEEP',
N'SQLTRACE_BUFFER_FLUSH', N'SQLTRACE_INCREMENTAL_FLUSH_SLEEP', N'SQLTRACE_WAIT_ENTRIES',
N'WAIT_FOR_RESULTS', N'WAITFOR', N'WAITFOR_TASKSHUTDOWN', N'WAIT_XTP_HOST_WAIT',
N'WAIT_XTP_OFFLINE_CKPT_NEW_LOG', N'WAIT_XTP_CKPT_CLOSE', N'WAIT_XTP_RECOVERY',
N'XE_BUFFERMGR_ALLPROCESSED_EVENT', N'XE_DISPATCHER_JOIN',
N'XE_DISPATCHER_WAIT', N'XE_LIVE_TARGET_TVF', N'XE_TIMER_EVENT')
AND waiting_tasks_count > 0)
SELECT
MAX (W1.wait_type) AS [WaitType],
CAST (MAX (W1.Percentage) AS DECIMAL (5,2)) AS [Wait Percentage],
CAST ((MAX (W1.WaitS) / MAX (W1.WaitCount)) AS DECIMAL (16,4)) AS [AvgWait_Sec],
CAST ((MAX (W1.ResourceS) / MAX (W1.WaitCount)) AS DECIMAL (16,4)) AS [AvgRes_Sec],
CAST ((MAX (W1.SignalS) / MAX (W1.WaitCount)) AS DECIMAL (16,4)) AS [AvgSig_Sec],
CAST (MAX (W1.WaitS) AS DECIMAL (16,2)) AS [Wait_Sec],
CAST (MAX (W1.ResourceS) AS DECIMAL (16,2)) AS [Resource_Sec],
CAST (MAX (W1.SignalS) AS DECIMAL (16,2)) AS [Signal_Sec],
MAX (W1.WaitCount) AS [Wait Count],
CAST (N'https://www.sqlskills.com/help/waits/' + W1.wait_type AS XML) AS [Help/Info URL]
FROM Waits AS W1
INNER JOIN Waits AS W2
ON W2.RowNum <= W1.RowNum
GROUP BY W1.RowNum, W1.wait_type
HAVING SUM (W2.Percentage) - MAX (W1.Percentage) < 99 -- percentage threshold
OPTION (RECOMPILE);select qs.spid,
qs.status, qs.blocked,
dbname=db_name(qs.dbid),
SUBSTRING(qt.text,qs.stmt_start/2 +1,
(case when qs.stmt_end = -1 then len(convert(nvarchar(max), qt.text)) * 2
else qs.stmt_end end -qs.stmt_start)/2) as QueryText,
qs.open_tran, qs.waitresource, qs.waittype,
qs.waittime, qs.cmd, qs.lastwaittype, qs.cpu, qs.physical_io,
qs.memusage,
last_batch=convert(varchar(26), last_batch,121),
login_time=convert(varchar(26), login_time,121),net_address,
qs.net_library, qs.dbid, qs.ecid, qs.kpid, qs.hostname, qs.hostprocess,
qs.loginame, qs.program_name, qs.nt_domain, qs.nt_username, qs.uid, qs.sid
from master.dbo.sysprocesses as qs
cross apply sys.dm_exec_sql_text(qs.sql_handle) as qt
where blocked!=0 or waittype != 0x0000
order by qs.dbidSelect cursor_id,
worker_time,
reads,
writes,
dormant_duration,
[text]
from sys.dm_exec_cursors (0) cross apply
sys.dm_exec_sql_text(sql_handle)
where session_id=80The following query gets to the original SQL query:
SELECT c.session_id, c.creation_time, c.reads, c.writes,
sp.blocked, sp.waitresource, loginame = UPPER(sp.loginame),
dbname = DB_NAME(sp.dbid), sp.status, open_tran = NULLIF(sp.open_tran, 0),
application = UPPER(program_name), command = sp.cmd, waittime = NULLIF(sp.waittime, 0),
sp.hostname, t.text as curtext, y.text as proctext
FROM sys.dm_exec_cursors (0) c
CROSS APPLY sys.dm_exec_sql_text (c.sql_handle) t
join sysprocesses sp on c.session_id=sp.spid
cross apply sys.dm_exec_sql_text(sp.sql_handle) y
where y.text like 'FETCH%'
order by c.reads desc- Navigate to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\Dynamics Server\6.0\01\Original (installed configuration). The last key, Original (installed configuration), is the key name for the current server configuration. If your system uses a different configuration that the original installed configuration, navigate to the currently active configuration.
- Create a string registry value called ‘connectioncontext’ and set the value to 1.
- Restart the AOS.
select cast(context_info as varchar(128)) as ci , *
from sys.dm_exec_sessions
where program_name like N'%Dynamics%'
and cast(context_info as varchar(128)) like N'%user1%'DBCC TRACESTATUS(-1)
GO
DBCC TRACESTATUS()
GOCHECKPOINT;
GO
DBCC DROPCLEANBUFFERS;
GO
DBCC FREEPROCCACHE
GO
update statistics WMSPICKINGROUTE with fullscan
ALTER INDEX ALL ON InventSum REBUILD with (ONLINE = ON)update SYSSQMSETTINGS SET GLOBALGUID = '{00000000-0000-0000-0000-000000000000}'
(restart AOS after that)
SELECT b.session_id AS [Session ID],
CAST(Db_name(a.database_id) AS VARCHAR(20)) AS [Database Name],
c.command,
Substring(st.TEXT, ( c.statement_start_offset / 2 ) + 1,
( (
CASE c.statement_end_offset
WHEN -1 THEN Datalength(st.TEXT)
ELSE c.statement_end_offset
END
-
c.statement_start_offset ) / 2 ) + 1)
statement_text,
Coalesce(Quotename(Db_name(st.dbid)) + N'.' + Quotename(
Object_schema_name(st.objectid,
st.dbid)) +
N'.' + Quotename(Object_name(st.objectid, st.dbid)), '')
command_text,
c.wait_type,
c.wait_time,
a.database_transaction_begin_time,
a.database_transaction_log_bytes_used / 1024.0 / 1024.0 AS [MB used],
a.database_transaction_log_bytes_used_system / 1024.0 / 1024.0 AS [MB used system],
a.database_transaction_log_bytes_reserved / 1024.0 / 1024.0 AS [MB reserved],
a.database_transaction_log_bytes_reserved_system / 1024.0 / 1024.0 AS [MB reserved system],
a.database_transaction_log_record_count AS [Record count]
FROM sys.dm_tran_database_transactions a
JOIN sys.dm_tran_session_transactions b
ON a.transaction_id = b.transaction_id
JOIN sys.dm_exec_requests c
CROSS APPLY sys.Dm_exec_sql_text(c.sql_handle) AS st
ON b.session_id = c.session_id
order by [Database Name], [Record count]just active queries
SELECT
r.session_id,
r.status,
r.start_time,
r.total_elapsed_time,
DB_NAME(r.database_id) AS database_name,
r.command,
r.wait_type,
r.wait_time,
r.logical_reads,
r.cpu_time,
s.login_name,
s.host_name,
s.program_name,
t.text AS sql_text,
qp.query_plan
FROM sys.dm_exec_requests r
JOIN sys.dm_exec_sessions s
ON r.session_id = s.session_id
OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) t
OUTER APPLY sys.dm_exec_query_plan(r.plan_handle) qp
WHERE r.session_id <> @@SPID -- exclude current session
and r.total_elapsed_time > 3000 --3 seconds
ORDER BY r.total_elapsed_time DESC;SELECT TOP 50
DB_NAME(CONVERT(int, qpa.value)) as [DataBase],
qt.[TEXT],
qs.execution_count,
qs.last_elapsed_time/1000 last_elapsed_time_in_mS,
qs.total_logical_reads, qs.last_logical_reads,
qs.total_logical_writes, qs.last_logical_writes,
qs.last_physical_reads, qs.total_physical_reads,
qs.total_worker_time/1000000 total_worker_time_in_S,
qs.last_worker_time/1000 last_worker_time_in_mS,
qs.total_elapsed_time/1000000 total_elapsed_time_in_S,
qs.last_execution_time,
DATEDIFF(MI,creation_time,GETDATE()) AS [Age of the Plan(Minutes)],
CASE WHEN cast(qp.query_plan as nvarchar(max)) LIKE N'%<MissingIndexGroup Impact="99%' THEN '!Has 99' ELSE '' END AS [Has 99%] ,
qp.query_plan
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) qt
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp
CROSS APPLY sys.dm_exec_plan_attributes(qs.plan_handle) qpa
where attribute = 'dbid'
ORDER BY qs.total_logical_reads DESC -- logical reads
-- ORDER BY qs.total_logical_writes DESC -- logical writes
--ORDER BY qs.total_worker_time DESC -- CPU time
--ORDER BY qs.total_physical_reads desc
-- DBCC FREEPROCCACHE to reset the counter
-- For Azure SQL - remove qpa from the query
-- ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE
EXEC sp_create_plan_guide @name = N'[AX_InventItemPriceDim]', @stmt = N'SELECT TOP 1 T1.ITEMID,T1.VERSIONID,T1.PRICETYPE,T1.INVENTDIMID,T1.MARKUP,T1.PRICEUNIT,T1.PRICE,T1.PRICECALCID,T1.UNITID,T1.PRICEALLOCATEMARKUP,T1.PRICEQTY,T1.STDCOSTTRANSDATE,T1.STDCOSTVOUCHER,T1.COSTINGTYPE,T1.ACTIVATIONDATE,T1.PRICESECCUR_RU,T1.MARKUPSECCUR_RU,T1.MODIFIEDDATETIME,T1.CREATEDDATETIME,T1.RECVERSION,T1.PARTITION,T1.RECID FROM INVENTITEMPRICE T1 WHERE (((T1.PARTITION=@P1) AND (T1.DATAAREAID=@P2)) AND (((T1.ITEMID=@P3) AND (T1.PRICETYPE=@P4)) AND (T1.ACTIVATIONDATE<=@P5))) AND EXISTS (SELECT TOP 1 ''x'' FROM INVENTDIM T2 WHERE (((T2.PARTITION=@P6) AND (T2.DATAAREAID=@P7)) AND ((T2.INVENTDIMID=T1.INVENTDIMID) AND (T2.INVENTSITEID=@P8)))) ORDER BY T1.ACTIVATIONDATE DESC,T1.CREATEDDATETIME DESC',
@type = N'SQL',
@module_or_batch = null,
@params = N'@P1 bigint,@P2 nvarchar(5),@P3 nvarchar(21),@P4 int,@P5 datetime2,@P6 bigint,@P7 nvarchar(5),@P8 nvarchar(11)',
@hints = N'OPTION (OPTIMIZE FOR UNKNOWN)'
@hints = N'OPTION(TABLE HINT (B, INDEX(I_698DIMIDIDX)), TABLE HINT ( a, INDEX(I_174ITEMDIMIDX)), loop join)'select top 100
plan_handle, st.text, qp.*
from
sys.dm_exec_cached_plans
cross apply
sys.dm_exec_sql_text(plan_handle) as st
cross apply
sys.dm_exec_query_plan(plan_handle) as qp
where text like N'%SELECT TOP 1 A.VENDGROUP,A.PURCHID,A.ORDERACCOUNT,A.INVOICEACCOUNT,A.INVOICEID,A.INVOICEDATE,A.DUEDATE,A.CASHDISC,A.CASHDISCDATE,A.QTY,A.VOLUME,A.WEIGHT,A.SUMLINEDISC,A.PREPAYMENT,A.SALESBALANCE,A.ENDDISC,A.INVOICEAMOUNT,A.CURRENCYCODE,A.EXCHRATE,A.ENTERPRISENUMBER,A.RETURNITEMNUM,A.TAXROUNDOFF,A.LEDGERVOUCHER,A.DIMENSION,A.DIMENSION2_,A.DIMENSION3_,A.DIMENSION4_,A.TAXPRINTONINVOICE,A.TAXSPECIFYBYLINE,A.DOCUMENTNUM,A.DOCUMENTDATE,A.COUNTRYREGIONID,A.INTRASTATDISPATCH,A.INVOICEROUNDOFF,A.SUMMARKUP,A.PAYMID,A.TAXGROUP,A.CASHDISCCODE,A.PAYMENT,A.POSTINGPROFILE,A.PAYMENTSCHED,A.INTERCOMPANYPOSTED,A.PURCHASETYPE,A.SUMTAX,A.PARMID,A.EXCHRATESECONDARY,A.TRIANGULATION,A.ITEMBUYERGROUPID,A.VATNUM,A.INTERNALINVOICEID,A.NUMBERSEQUENCEGROUP,A.INCLTAX,A.PAYMDAYID,A.DLVTERM,A.DLVMODE,A.FIXEDDUEDATE,A.INTERCOMPANYCOMPANYID,A.INTERCOMPANYSALESID,A.INTERCOMPANYLEDGERVOUCHER,A.PROFORMA,A.LANGUAGEID,A.INVOICEAMOUNTMST,A.SUMMARKUPMST,A.ENDDISCMST,A.REVERSECHARGE_UK,A.PURCHRECEIPTDATE_W,A.VATONPAYMENT_RU,A.CORRECT_RU,A.INVENTPROFILETYPE_RU,A.CORRECTEDINVOICEID_RU,A.CORRECTEDINVOICEDATE_RU,A.EUSALESLIST_HU,A.SUMTAX_W,A.EXCHRATE_W,A.INVENTBAILEERECEIPTREPORTID_RU,A.REFORIGINALINVOICE_RU,A.CORRECTIONTYPE_RU,A.NONREALREVENUE_RU,A.OFFSESSIONID_RU,A.CONSIGNEEACCOUNT_RU,A.CONSIGNORACCOUNT_RU,A.FACTUREDFULLY_RU,A.ATTORNEYISSUEDNAME_RU,A.ATTORNEYID_RU,A.ATTORNEYDATE_RU,A.RCONTRACTCODE,A.RCONTRACTACCOUNT,A.LISTCODE_EE,A.EUINVOICERECID_PL,A.KAR_APPLICIMPORTEDGOODSEX50001,A.KAR_APPLICIMPORTEDGOODSEX50004,A.KAR_INVENTTRANSFERCREATED,A.KAR_RELATEDTRANSFERSHIPPED,A.CREATEDDATETIME,A.DEL_CREATEDTIME,A.CREATEDBY,A.CREATEDTRANSACTIONID,A.RECVERSION,A.RECID FROM VENDINVOICEJOUR A WHERE ((DATAAREAID=N''ru'') AND (((((INVOICEID=@P1) AND (INVOICEDATE=@P2)) AND (PURCHID=@P3)) AND (NUMBERSEQUENCEGROUP=@P4)) AND (INTERNALINVOICEID=@P5)))%'
DBCC FREEPROCCACHE (0x060005005BB88A134041B2A6120000000000000000000000)Normal tables that were disabled by the config key. In this case for every call AX created a temporary table, that affects the performance
Check are there any table in the DB cache
declare @p1 nvarchar(100)
declare @pTxt nvarchar(1000)
set @p1 = 'INSERT INTO tempdb."DBO".t';
select tabId , b.[name] from (select top 10000
SUBSTRING ( st.text ,CHARINDEX(@p1, st.text)+len(@p1) , CHARINDEX('_', st.text) - CHARINDEX(@p1, st.text)-len(@p1) ) as tabId
from
sys.dm_exec_cached_plans
cross apply
sys.dm_exec_sql_text(plan_handle) as st
where text like (N'%' + @p1 + N'%') and
CHARINDEX('_', st.text) - CHARINDEX(@p1, st.text)-len(@p1) > 1) a, sqldictionary b
where a.tabId <> '' and TRY_CONVERT (int , a.tabId )= b.TABLEID and b.FIELDID = 0
group by a.tabId, b.[name]static boolean dev_isTableEnabled(Common _table)
{
boolean res = true;
DictTable dictTable;
;
if (! _table.TableId || _table.isTmp())
{
res = false;
}
else
{
dictTable = new DictTable(_table.TableId);
if (dictTable && dictTable.configurationKeyId() && ! isConfigurationkeyEnabled(dictTable.configurationKeyId()))
{
res = false;
}
}
return res;
}
if (! dev_isTableEnabled(assetParameters))
{
return assetParameters;
}CREATE TABLE tempdb."DBO".t1162_5E2D5DA7EC324CC6BF0BA2281C0D58B8 (KEY_ INT NOT NULL DEFAULT 0 ,DEPRECIATIONMIN NUMERIC(32,16) NOT NULL DEFAULT 0 ,MULTIACQUISITION INT NOT NULL DEFAULT 0 ,ADDITIONALACQDEPRECIATION INTstatic void TRUD_SetSQLMonitorFlag(Args _args)
{
#LOCALMACRO.FLAG_TraceInfoQueryTable (1 << 11) #ENDMACRO
#LOCALMACRO.FLAG_SQLTrace (1 << 8) #ENDMACRO
#LOCALMACRO.FLAG_TraceInfoDeadLockTable (1 << 15) #ENDMACRO
UserInfo userInfo;
;
//To remove use ^
while select userInfo
where userInfo.id == 'denis'
{
userInfo.debugInfo = userInfo.debugInfo | #FLAG_SQLTrace;
userInfo.traceInfo = userInfo.traceInfo | #FLAG_TraceInfoQueryTable;
userInfo.traceInfo = userInfo.traceInfo | #FLAG_TraceInfoDeadLockTable;
userInfo.querytimeLimit = 2000;
userInfo.skipTTSCheck(true);
userInfo.update();
}
}//delete similar traces
static void dev1_deletesystrace(Args _args)
{
SysTraceTableSQL sysTraceTableSQL;
SysTraceTableSQL sysTraceTableSQLOrig;
int rows;
;
select sysTraceTableSQLOrig
where sysTraceTableSQLOrig.RecId == 134324;
while select sysTraceTableSQL
where sysTraceTableSQL.Category == SQLTraceCategory::QueryTime &&
sysTraceTableSQL.createdDate == sysTraceTableSQLOrig.createdDate &&
sysTraceTableSQL.RecId != sysTraceTableSQLOrig.RecId
{
if (
sysTraceTableSQL.Statement == sysTraceTableSQLOrig.Statement &&
sysTraceTableSQL.callStack == sysTraceTableSQLOrig.callStack
)
{
rows++;
sysTraceTableSQL.skipTTSCheck(true);
//sysTraceTableSQL.delete();
}
}
info(strFmt("%1", rows));
}static void dev1_sysdatabaseLog(Args _args)
{
SysDatabaseLog sysdatabaseLog;
TextBuffer tb = new TextBuffer();
;
tb.appendText(strFmt("%1\t%2\t%3\n",
"Table", "LogType", "Record Count"));
while select count(recid) from sysdatabaseLog
group by LogType, table
{
tb.appendText(strFmt("%1\t%2\t%3\n", tableid2name(sysdatabaseLog.table), sysdatabaseLog.LogType, sysdatabaseLog.RecId));
}
tb.toClipboard();
}
static void trud_copyBatchInfo(Args _args)
{
Batch batch;
TextBuffer tb = new TextBuffer();
;
tb.appendText(strFmt("%1\t%2\t%3\t%4\t%5\t%6\t%7\t%8\n",
"Batch job ID" , "Status" , "Job description" , "Actual start date/time" ,
"End date/time" , "Company" , "Partition Key" , "User ID"));
while select batch
where batch.EndDate > 30\12\2018
{
tb.appendText(strFmt(strFmt("%1\t%2\t%3\t%4\t%5\t%6\t%7\t%8\n",
batch.RecId, batch.Status, batch.ClassDescription(), strFmt("%1 %2", batch.StartDate, time2str(batch.startTime, 1, 1)),
strFmt("%1 %2", batch.EndDate, time2str(batch.endtime,1,1)), batch.Company, batch.TableId, batch.CreatedBy)
));
}
Box::info("done");
tb.toClipboard();
}static void numberSeqCheck(Args _args)
{
NumberSequenceTable numberSequenceTable;
NumberSequenceReference numberSequenceReference, numberSequenceReference2;
NumberSequenceScope numberSequenceScope;
DataArea dataArea;
real ratio;
int i;
;
info("Less that 25%");
while select numberSequenceTable
{
ratio = (numberSequenceTable.Highest - numberSequenceTable.NextRec ) / (numberSequenceTable.Highest - numberSequenceTable.Lowest) ;
if (ratio < 0.25 )
{
info(strFmt("Code %1, txt %2, Lowest %3, Highest %4, NextRec %5", numberSequenceTable.NumberSequence, numberSequenceTable.Txt,
numberSequenceTable.Lowest, numberSequenceTable.Highest, numberSequenceTable.NextRec));
}
}
info("Continuous");
numberSequenceTable = null;
while select numberSequenceTable
where numberSequenceTable.Continuous &&
(numberSequenceTable.NextRec > numberSequenceTable.Lowest + 1000)
{
info(strFmt("Code %1, txt %2, Lowest %3, Highest %4, NextRec %5", numberSequenceTable.NumberSequence, numberSequenceTable.Txt,
numberSequenceTable.Lowest, numberSequenceTable.Highest, numberSequenceTable.NextRec));
}
info("Not existing");
numberSequenceTable = null;
ttsBegin;
while select forUpdate numberSequenceTable
join numberSequenceReference
where numberSequenceReference.NumberSequenceId == numberSequenceTable.RecId
join numberSequenceScope
where numberSequenceScope.RecId == numberSequenceReference.NumberSequenceScope &&
numberSequenceScope.dataArea
notexists join dataArea
where dataArea.id == numberSequenceScope.dataArea
{
numberSequenceReference2 = null;
select firstonly numberSequenceReference2
where numberSequenceReference2.NumberSequenceId == numberSequenceTable.RecId &&
numberSequenceReference2.RecId != numberSequenceReference.RecId;
if (! numberSequenceReference2.RecId)
{
if (i < 100)
{
info(strFmt("Code %1, txt %2, Lowest %3, Highest %4, NextRec %5", numberSequenceTable.NumberSequence, numberSequenceTable.Txt,
numberSequenceTable.Lowest, numberSequenceTable.Highest, numberSequenceTable.NextRec));
}
i++;
/*
numberSequenceScope.dodelete();
numberSequenceReference.dodelete();
numberSequenceTable.doDelete();
*/
}
}
ttsCommit;
info(strFmt("Total number %1", i));
}#AOT
static void trud_checkCache(Args _args) {
TreeNode treeNodeTable;
TreeNodeIterator treeNodeIteratorTable;
DictTable dictTable;
Common anyRecord;
SysOperationProgress operationProgress = new SysOperationProgress ();
;
treeNodeTable = infolog.findNode(#TablesPath);
treeNodeIteratorTable = treeNodeTable.aotiterator();
treeNodeTable = treeNodeIteratorTable.next();
operationProgress.setCaption("Check...");
operationProgress.setTotal(7000); //approximately
while (treeNodeTable)
{
//if (treeNodeTable.treeNo == TreeNodeType:: UtilElementType::Table)
{
dictTable = new DictTable(treeNodeTable.applObjectId());
if (dictTable && dictTable.cacheLookup() == RecordCacheLevel::EntireTable)
{
anyRecord = null;
anyRecord = dictTable.makeRecord();
select crossCompany count(RecId) from anyRecord;
if (anyRecord.RecId > 1000)
{
info(strFmt("%1, %2", dictTable.name(), anyRecord.RecId));
}
}
}
operationProgress.incCount();
treeNodeTable = treeNodeIteratorTable.next();
}
}- Download the http://www.roylongbottom.org.uk/win64.zip
- Run the program dhry164int32.exe example 10 times
dhry264int64
12621 E5-2637 v2 8467 E5-2640 v2 (2GHz), 10082 E5-2640(2.5GHz)
dhry164int32 27605 E5-2637 v2, 18581 E5-2640 v2 (2GHz), 21130 E5-2640(2.5GHz)
Crystal disk mark
How to Use CrystalDiskMark 7 to Test Your SQL Server’s Storage
8 RAID 10 Inner RAID
IF OBJECT_ID('tempdb..#recordsToDelete') IS NOT NULL DROP TABLE #recordsToDelete
IF OBJECT_ID('tempdb..#temp_hash') IS NOT NULL
DROP TABLE #temp_hash
CREATE TABLE #temp_hash (RECID BIGINT)
declare @step int
declare @isLastStep int = 0;
WHILE (@isLastStep = 0)
BEGIN
select top 1000000 RECID into #recordsToDelete
FROM [dbo].ZINFOLOGHISTORY AS hashtbl --TABLE HERE
WHERE hashtbl.CREATEDDATETIME <(GETDATE() -30);
IF (@@ROWCOUNT < 1000000) SET @isLastStep = 1
CREATE NONCLUSTERED INDEX [##_RECID] ON #recordsToDelete (RECID ASC)
set @step= 0
WHILE (@step < 100)
BEGIN
SET @step = @step + 1
TRUNCATE TABLE #temp_hash
INSERT INTO #temp_hash(RECID) SELECT TOP 10000 RECID FROM #recordsToDelete;
IF (@@ROWCOUNT = 0) break;
--------------------------------------------------------------
delete hs
FROM [dbo].ZINFOLOGHISTORY hs --TABLE HERE
INNER JOIN #temp_hash AS JN ON hs.RECID = JN.RECID
----------------------------
delete from #recordsToDelete from #recordsToDelete as dt inner join #temp_hash as dl
on dl.RECID =dt.RECID
END
DROP TABLE #recordsToDelete
END
DROP TABLE #temp_hash;
--Another option (about 30sec per 100k lines)
declare @rowCount int = -1;
declare @curStep int = 0
while(@rowCount <> 0 AND @curStep < 10000) begin
WITH Comments_ToBeDeleted AS (
SELECT TOP 10000 *
FROM BatchJobHistory
--ORDER BY CREATEDDATETIME
)
DELETE FROM Comments_ToBeDeleted
WHERE CREATEDDATETIME <(GETDATE() - 30)
set @rowCount = @@rowCount;
set @curStep = @curStep + 1;
endDECLARE @ThresholdTimeMS INT = 600
DECLARE @ThresholdNumOfLocks INT = 0
DECLARE @NumOfLocks INT
DECLARE @LocksTime INT
SELECT @NumOfLocks = count(*), @LocksTime = max(wait_duration_ms)
FROM sys.dm_os_waiting_tasks
WHERE blocking_session_id <> 0
AND [wait_type] LIKE N'LCK_%'
IF @NumOfLocks > @ThresholdNumOfLocks AND @LocksTime > @ThresholdTimeMS
BEGIN
DECLARE @Msg NVARCHAR(max)
DECLARE @HTMLStr NVARCHAR(max)
SET @Msg = N'Blocking alert. Blocked sessions:'
+ CAST(@NumOfLocks AS NVARCHAR(10))
+ N' Blocked time:'
+ CAST(@LocksTime / 1000 AS NVARCHAR(10))
+ N' sec';
DECLARE @oper_email NVARCHAR(100)
SET @oper_email = (SELECT email_address from msdb.dbo.sysoperators WHERE name = N'OperatorName')
DECLARE @body NVARCHAR(MAX)
SET @body = N'<table>'
+ N'<tr><th>session_id</th><th>wait_duration_ms</th><th>wait_type</th><th>blocking_session_id</th><th>resource_description</th><th>program_name</th><th>text</th></tr>'
+ CAST((
SELECT w.session_id AS td
,w.wait_duration_ms AS td
,w.wait_type AS td
,w.blocking_session_id AS td
,w.resource_description AS td
,s.program_name AS td
,t.text AS td
FROM sys.dm_os_waiting_tasks w
INNER JOIN sys.dm_exec_sessions s
ON w.session_id = s.session_id
INNER JOIN sys.dm_exec_requests r
ON s.session_id = r.session_id
OUTER APPLY sys.dm_exec_sql_text (r.sql_handle) t
WHERE s.is_user_process = 1
AND w.[wait_type] LIKE N'LCK_%'
FOR XML RAW('tr'), ELEMENTS
) AS NVARCHAR(MAX))
+ N'</table>'
SET @body = REPLACE(@body, '<tdc>', '<td class="center">')
SET @body = REPLACE(@body, '</tdc>', '</td>')
SET @HTMLStr = N'<html><body>' + @Msg + N'<br><br>' + @body + N'</body></html>';
SELECT @HTMLStr --DEBUG
SET @oper_email = 'trud81@gmail.com' --DEBUG
EXEC msdb.dbo.sp_send_dbmail
@recipients = @oper_email,
@subject = @Msg,
@body = @HTMLStr,
@body_format = 'HTML' ;
--RAISERROR (911421,10,1,@msg) WITH LOG;
ENDhttps://denistrunin.com/understanding-sql-blocking/
Form based on view – sorting by RecId is added automatically. It is better to remove it by adding sorting by another field
View_ds.queryBuildDataSource().sortClear();
View _ds.queryBuildDataSource().addSortField(fieldNum(View, F1), SortOrder::Descending);