Option Explicit On Imports DigitalData.Modules.Database Imports DigitalData.Modules.Logging Imports Quartz Public Class DatatableJob Implements IJob Private Const COMMAND_SQL_TIMEOUT = 240 Public Function Execute(context As IJobExecutionContext) As Task Implements IJob.Execute Dim oJobData = context.MergedJobDataMap Dim oLogConfig As LogConfig = oJobData.Item("LogConfig") Dim oCronJobId As Integer = oJobData.Item("CronJobId") Dim oCronJobTitle As String = oJobData.Item("CronJobTitle") Dim oLogger As Logger = oLogConfig.GetLogger() Dim oStopWatch As New Stopwatch() Dim oResult As New JobResult() oLogger.Info("Running Datatable Job [{0}]/[{1}]", context.JobDetail.Key, oCronJobTitle) Dim oJobStopWatch As New Stopwatch() ' ← Gesamt-Messung für den gesamten Job oJobStopWatch.Start() Try Dim oMSSQL As MSSQLServer = oJobData.Item("MSSQL") Dim oCronSQL As String = $"SELECT * FROM TBAPPSERV_CRON_DETAIL WITH (NOLOCK) WHERE CRON_ID = {oCronJobId}" Dim oCronDetails As DataTable = oMSSQL.GetDatatable(oCronSQL) For Each oRow As DataRow In oCronDetails.Rows Dim oDatatableName As String = IIf(IsDBNull(oRow.Item("DT_NAME")), String.Empty, oRow.Item("DT_NAME")) Dim oParentColumn As String = IIf(IsDBNull(oRow.Item("DT_COLUMN")), String.Empty, oRow.Item("DT_COLUMN")) Dim oChildColumn As String = IIf(IsDBNull(oRow.Item("CHILD_DT_COLUMN")), String.Empty, oRow.Item("CHILD_DT_COLUMN")) Dim oConnectionId As Integer = IIf(IsDBNull(oRow.Item("CON_ID")), 0, oRow.Item("CON_ID")) Dim oTitle As String = IIf(IsDBNull(oRow.Item("TITLE")), String.Empty, oRow.Item("TITLE")) Dim oSQL As String = IIf(IsDBNull(oRow.Item("COMMAND")), String.Empty, oRow.Item("COMMAND")) Dim oIndexColumns As String = IIf(IsDBNull(oRow.Item("INDEX_COLUMNS")), String.Empty, oRow.Item("INDEX_COLUMNS")) Try oLogger.Debug("Running Command-Job [{0}]", oTitle) oLogger.Debug("Datatable Name: {0}", oDatatableName) oLogger.Debug("Connection Id: {0}", oConnectionId) oStopWatch.Restart() Dim oConnectionString As String = oMSSQL.Get_ConnectionStringforID(oConnectionId) Dim oTable = oMSSQL.GetDatatableWithConnection(oSQL, oConnectionString, COMMAND_SQL_TIMEOUT) oTable.TableName = oDatatableName oStopWatch.Stop() Dim oQueryMs = oStopWatch.ElapsedMilliseconds ' ✅ Schwellwert-Warnung: Query dauert länger als 10s If oQueryMs > 10000 Then oLogger.Warn("⚠ SLOW QUERY [{0}] | Datatable=[{1}] | Duration=[{2}ms] | SQL=[{3}]", oTitle, oDatatableName, oQueryMs, oSQL.Substring(0, Math.Min(200, oSQL.Length))) Else oLogger.Debug("[Time] Getting Data From DB: {0}ms", oQueryMs) End If oStopWatch.Restart() Dim oView As DataView = Nothing ' This creates an Index for the columns specified in INDEX_COLUMNS to speed up calls to 'Table.Select'! If oIndexColumns <> String.Empty Then oLogger.Debug("Adding indexes for Table: [{0}]", oIndexColumns) oView = New DataView(oTable) With { .Sort = oIndexColumns } End If oStopWatch.Stop() oLogger.Debug("[Time] Creating Indexes: {0}ms", oStopWatch.ElapsedMilliseconds) oStopWatch.Restart() oLogger.Debug("Result Datatable [{0}] contains [{1}] rows", oTable.TableName, oTable.Rows.Count) Dim oResultTable = New JobResult.ResultTable() With { .Table = oTable, .View = oView, .DetailRow = oRow } Dim oChildTableNAme As String = IIf(IsDBNull(oRow.Item("CHILD_DT_NAME")), String.Empty, oRow.Item("CHILD_DT_NAME")) If oChildTableNAme <> String.Empty Then oLogger.Debug("Child Datatable [{0}] defined, Relation: Parent [{1}] -> Child [{2}]", oChildTableNAme, oParentColumn, oChildColumn) Dim oChildTable As DataTable = oMSSQL.GetDatatableWithConnection($"SELECT * FROM {oChildTableNAme}", oConnectionString) oChildTable.TableName = oChildTableNAme oLogger.Debug("Child Datatable [{0}] contains [{1}] rows", oChildTable.TableName, oChildTable.Rows.Count) oResultTable.ChildTable = oChildTable oResultTable.ChildRelationColumn = oChildColumn oResultTable.TableRelationColumn = oParentColumn End If oStopWatch.Stop() oLogger.Debug("[Time] Adding Relations: {0}ms", oStopWatch.ElapsedMilliseconds) oLogger.Info("✔ Fetched Datatable [{0}]", oDatatableName) oResult.Tables.Add(oResultTable) Catch ex As Exception oLogger.Warn("⚠ Error while saving Table: [{0}]", oDatatableName) oLogger.Error(ex) End Try Next ' Das Ergebnis speichern context.Result = oResult oJobStopWatch.Stop() ' ✅ Gesamt-Performance-Log pro Job-Ausführung Dim oTotalMs = oJobStopWatch.ElapsedMilliseconds If oTotalMs > 30000 Then oLogger.Warn("⚠ SLOW JOB [{0}] | Tables=[{1}] | TotalDuration=[{2}ms]", oCronJobTitle, oResult.Tables.Count, oTotalMs) Else oLogger.Info("✔✔ Fetched [{0}] Datatables in [{1}ms] ✔✔", oResult.Tables.Count, oTotalMs) End If Catch ex As Exception oLogger.Error(ex) oLogger.Warn("⚠ Unhandled exception while executing SQL for Datatable {0}", oCronJobTitle) End Try Return Task.FromResult(True) End Function End Class