taurusdb-core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -0
- package/dist/auth/secret-resolver.d.ts +16 -0
- package/dist/auth/secret-resolver.js +64 -0
- package/dist/auth/sql-profile-loader/env-source.d.ts +3 -0
- package/dist/auth/sql-profile-loader/env-source.js +94 -0
- package/dist/auth/sql-profile-loader/file-source.d.ts +6 -0
- package/dist/auth/sql-profile-loader/file-source.js +40 -0
- package/dist/auth/sql-profile-loader/loader.d.ts +16 -0
- package/dist/auth/sql-profile-loader/loader.js +81 -0
- package/dist/auth/sql-profile-loader/parsing.d.ts +14 -0
- package/dist/auth/sql-profile-loader/parsing.js +216 -0
- package/dist/auth/sql-profile-loader/runtime-override.d.ts +14 -0
- package/dist/auth/sql-profile-loader/runtime-override.js +52 -0
- package/dist/auth/sql-profile-loader/types.d.ts +64 -0
- package/dist/auth/sql-profile-loader/types.js +1 -0
- package/dist/auth/sql-profile-loader.d.ts +4 -0
- package/dist/auth/sql-profile-loader.js +3 -0
- package/dist/capability/feature-matrix.d.ts +5 -0
- package/dist/capability/feature-matrix.js +237 -0
- package/dist/capability/probe.d.ts +19 -0
- package/dist/capability/probe.js +139 -0
- package/dist/capability/types.d.ts +49 -0
- package/dist/capability/types.js +16 -0
- package/dist/capability/version.d.ts +3 -0
- package/dist/capability/version.js +47 -0
- package/dist/cloud/auth.d.ts +26 -0
- package/dist/cloud/auth.js +198 -0
- package/dist/cloud/instances.d.ts +46 -0
- package/dist/cloud/instances.js +224 -0
- package/dist/config/env.d.ts +1 -0
- package/dist/config/env.js +194 -0
- package/dist/config/index.d.ts +6 -0
- package/dist/config/index.js +21 -0
- package/dist/config/redaction.d.ts +2 -0
- package/dist/config/redaction.js +19 -0
- package/dist/config/schema.d.ts +417 -0
- package/dist/config/schema.js +100 -0
- package/dist/context/datasource-resolver.d.ts +19 -0
- package/dist/context/datasource-resolver.js +71 -0
- package/dist/context/session-context.d.ts +26 -0
- package/dist/context/session-context.js +1 -0
- package/dist/diagnostics/metrics-source.d.ts +65 -0
- package/dist/diagnostics/metrics-source.js +280 -0
- package/dist/diagnostics/slow-sql-source/das-source.d.ts +43 -0
- package/dist/diagnostics/slow-sql-source/das-source.js +170 -0
- package/dist/diagnostics/slow-sql-source/factory.d.ts +5 -0
- package/dist/diagnostics/slow-sql-source/factory.js +87 -0
- package/dist/diagnostics/slow-sql-source/parsers.d.ts +7 -0
- package/dist/diagnostics/slow-sql-source/parsers.js +125 -0
- package/dist/diagnostics/slow-sql-source/taurus-api-source.d.ts +42 -0
- package/dist/diagnostics/slow-sql-source/taurus-api-source.js +149 -0
- package/dist/diagnostics/slow-sql-source/types.d.ts +40 -0
- package/dist/diagnostics/slow-sql-source/types.js +1 -0
- package/dist/diagnostics/slow-sql-source/utils.d.ts +20 -0
- package/dist/diagnostics/slow-sql-source/utils.js +170 -0
- package/dist/diagnostics/slow-sql-source.d.ts +4 -0
- package/dist/diagnostics/slow-sql-source.js +3 -0
- package/dist/diagnostics/types.d.ts +189 -0
- package/dist/diagnostics/types.js +39 -0
- package/dist/engine/data-access/locks.d.ts +8 -0
- package/dist/engine/data-access/locks.js +146 -0
- package/dist/engine/data-access/processlist.d.ts +4 -0
- package/dist/engine/data-access/processlist.js +56 -0
- package/dist/engine/data-access/statements.d.ts +10 -0
- package/dist/engine/data-access/statements.js +203 -0
- package/dist/engine/data-access/storage.d.ts +6 -0
- package/dist/engine/data-access/storage.js +96 -0
- package/dist/engine/data-access.d.ts +4 -0
- package/dist/engine/data-access.js +4 -0
- package/dist/engine/diagnostics.d.ts +7 -0
- package/dist/engine/diagnostics.js +7 -0
- package/dist/engine/helper-modules/diagnostics.d.ts +57 -0
- package/dist/engine/helper-modules/diagnostics.js +322 -0
- package/dist/engine/helper-modules/parsers.d.ts +13 -0
- package/dist/engine/helper-modules/parsers.js +283 -0
- package/dist/engine/helper-modules/sql.d.ts +12 -0
- package/dist/engine/helper-modules/sql.js +119 -0
- package/dist/engine/helper-modules/types.d.ts +103 -0
- package/dist/engine/helper-modules/types.js +1 -0
- package/dist/engine/helpers.d.ts +4 -0
- package/dist/engine/helpers.js +4 -0
- package/dist/engine/runtime.d.ts +20 -0
- package/dist/engine/runtime.js +385 -0
- package/dist/engine/types.d.ts +125 -0
- package/dist/engine/types.js +1 -0
- package/dist/engine/workflows/connection-spike.d.ts +4 -0
- package/dist/engine/workflows/connection-spike.js +316 -0
- package/dist/engine/workflows/db-hotspot.d.ts +4 -0
- package/dist/engine/workflows/db-hotspot.js +182 -0
- package/dist/engine/workflows/lock-contention-helpers/entities.d.ts +9 -0
- package/dist/engine/workflows/lock-contention-helpers/entities.js +58 -0
- package/dist/engine/workflows/lock-contention-helpers/no-match.d.ts +3 -0
- package/dist/engine/workflows/lock-contention-helpers/no-match.js +65 -0
- package/dist/engine/workflows/lock-contention-helpers/report.d.ts +21 -0
- package/dist/engine/workflows/lock-contention-helpers/report.js +104 -0
- package/dist/engine/workflows/lock-contention-helpers/root-cause.d.ts +4 -0
- package/dist/engine/workflows/lock-contention-helpers/root-cause.js +79 -0
- package/dist/engine/workflows/lock-contention-helpers/signals.d.ts +22 -0
- package/dist/engine/workflows/lock-contention-helpers/signals.js +34 -0
- package/dist/engine/workflows/lock-contention-helpers.d.ts +5 -0
- package/dist/engine/workflows/lock-contention-helpers.js +5 -0
- package/dist/engine/workflows/lock-contention.d.ts +4 -0
- package/dist/engine/workflows/lock-contention.js +67 -0
- package/dist/engine/workflows/service-latency.d.ts +4 -0
- package/dist/engine/workflows/service-latency.js +262 -0
- package/dist/engine/workflows/slow-query-helpers.d.ts +41 -0
- package/dist/engine/workflows/slow-query-helpers.js +253 -0
- package/dist/engine/workflows/slow-query.d.ts +4 -0
- package/dist/engine/workflows/slow-query.js +156 -0
- package/dist/engine/workflows/storage-pressure-helpers.d.ts +12 -0
- package/dist/engine/workflows/storage-pressure-helpers.js +281 -0
- package/dist/engine/workflows/storage-pressure.d.ts +4 -0
- package/dist/engine/workflows/storage-pressure.js +27 -0
- package/dist/engine/workflows/top-slow-sql.d.ts +4 -0
- package/dist/engine/workflows/top-slow-sql.js +222 -0
- package/dist/engine.d.ts +77 -0
- package/dist/engine.js +240 -0
- package/dist/executor/adapters/mysql.d.ts +2 -0
- package/dist/executor/adapters/mysql.js +114 -0
- package/dist/executor/connection-pool.d.ts +105 -0
- package/dist/executor/connection-pool.js +236 -0
- package/dist/executor/explain.d.ts +5 -0
- package/dist/executor/explain.js +119 -0
- package/dist/executor/query-tracker.d.ts +45 -0
- package/dist/executor/query-tracker.js +83 -0
- package/dist/executor/result-normalizer.d.ts +6 -0
- package/dist/executor/result-normalizer.js +47 -0
- package/dist/executor/sql-executor.d.ts +32 -0
- package/dist/executor/sql-executor.js +250 -0
- package/dist/executor/types.d.ts +70 -0
- package/dist/executor/types.js +1 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.js +21 -0
- package/dist/safety/confirmation-store.d.ts +44 -0
- package/dist/safety/confirmation-store.js +130 -0
- package/dist/safety/guardrail.d.ts +39 -0
- package/dist/safety/guardrail.js +99 -0
- package/dist/safety/parser/adapter.d.ts +10 -0
- package/dist/safety/parser/adapter.js +72 -0
- package/dist/safety/parser/ast-utils.d.ts +10 -0
- package/dist/safety/parser/ast-utils.js +167 -0
- package/dist/safety/parser/features.d.ts +12 -0
- package/dist/safety/parser/features.js +113 -0
- package/dist/safety/parser/index.d.ts +2 -0
- package/dist/safety/parser/index.js +1 -0
- package/dist/safety/parser/types.d.ts +76 -0
- package/dist/safety/parser/types.js +1 -0
- package/dist/safety/redaction.d.ts +34 -0
- package/dist/safety/redaction.js +186 -0
- package/dist/safety/sql-classifier.d.ts +19 -0
- package/dist/safety/sql-classifier.js +43 -0
- package/dist/safety/sql-validator.d.ts +19 -0
- package/dist/safety/sql-validator.js +143 -0
- package/dist/schema/adapters/mysql.d.ts +16 -0
- package/dist/schema/adapters/mysql.js +287 -0
- package/dist/schema/introspector.d.ts +70 -0
- package/dist/schema/introspector.js +40 -0
- package/dist/taurus/flashback.d.ts +36 -0
- package/dist/taurus/flashback.js +149 -0
- package/dist/taurus/recycle-bin.d.ts +14 -0
- package/dist/taurus/recycle-bin.js +61 -0
- package/dist/utils/formatter.d.ts +70 -0
- package/dist/utils/formatter.js +60 -0
- package/dist/utils/hash.d.ts +2 -0
- package/dist/utils/hash.js +247 -0
- package/dist/utils/id.d.ts +2 -0
- package/dist/utils/id.js +11 -0
- package/dist/utils/logger.d.ts +9 -0
- package/dist/utils/logger.js +39 -0
- package/package.json +46 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
export type DiagnosticToolName = "diagnose_service_latency" | "diagnose_db_hotspot" | "find_top_slow_sql" | "diagnose_slow_query" | "diagnose_connection_spike" | "diagnose_lock_contention" | "diagnose_storage_pressure";
|
|
2
|
+
export type DiagnosticStatus = "ok" | "inconclusive" | "not_applicable";
|
|
3
|
+
export type DiagnosticSeverity = "info" | "warning" | "high" | "critical";
|
|
4
|
+
export type DiagnosticEvidenceLevel = "basic" | "standard" | "full";
|
|
5
|
+
export type DiagnosticConfidence = "low" | "medium" | "high";
|
|
6
|
+
export interface DiagnosisWindow {
|
|
7
|
+
from?: string;
|
|
8
|
+
to?: string;
|
|
9
|
+
relative?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface DiagnosticBaseInput {
|
|
12
|
+
datasource?: string;
|
|
13
|
+
database?: string;
|
|
14
|
+
timeRange?: DiagnosisWindow;
|
|
15
|
+
evidenceLevel?: DiagnosticEvidenceLevel;
|
|
16
|
+
includeRawEvidence?: boolean;
|
|
17
|
+
maxCandidates?: number;
|
|
18
|
+
}
|
|
19
|
+
export interface DiagnoseSlowQueryInput extends DiagnosticBaseInput {
|
|
20
|
+
sql?: string;
|
|
21
|
+
sqlHash?: string;
|
|
22
|
+
digestText?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface DiagnoseServiceLatencyInput extends DiagnosticBaseInput {
|
|
25
|
+
user?: string;
|
|
26
|
+
clientHost?: string;
|
|
27
|
+
symptom?: "latency" | "timeout" | "cpu" | "connection_growth";
|
|
28
|
+
}
|
|
29
|
+
export interface DiagnoseDbHotspotInput extends DiagnosticBaseInput {
|
|
30
|
+
scope?: "sql" | "table" | "session";
|
|
31
|
+
}
|
|
32
|
+
export interface FindTopSlowSqlInput extends DiagnosticBaseInput {
|
|
33
|
+
topN?: number;
|
|
34
|
+
sortBy?: "avg_latency" | "total_latency" | "exec_count" | "lock_time";
|
|
35
|
+
}
|
|
36
|
+
export interface DiagnoseConnectionSpikeInput extends DiagnosticBaseInput {
|
|
37
|
+
user?: string;
|
|
38
|
+
clientHost?: string;
|
|
39
|
+
compareBaseline?: boolean;
|
|
40
|
+
}
|
|
41
|
+
export interface DiagnoseLockContentionInput extends DiagnosticBaseInput {
|
|
42
|
+
table?: string;
|
|
43
|
+
blockerSessionId?: string;
|
|
44
|
+
}
|
|
45
|
+
export interface DiagnoseStoragePressureInput extends DiagnosticBaseInput {
|
|
46
|
+
scope?: "instance" | "database" | "table";
|
|
47
|
+
table?: string;
|
|
48
|
+
}
|
|
49
|
+
export interface DiagnosticRootCauseCandidate {
|
|
50
|
+
code: string;
|
|
51
|
+
title: string;
|
|
52
|
+
confidence: DiagnosticConfidence;
|
|
53
|
+
rationale: string;
|
|
54
|
+
}
|
|
55
|
+
export interface DiagnosticSuspiciousSql {
|
|
56
|
+
sqlHash?: string;
|
|
57
|
+
digestText?: string;
|
|
58
|
+
reason: string;
|
|
59
|
+
}
|
|
60
|
+
export interface DiagnosticSuspiciousSession {
|
|
61
|
+
sessionId?: string;
|
|
62
|
+
user?: string;
|
|
63
|
+
state?: string;
|
|
64
|
+
reason: string;
|
|
65
|
+
}
|
|
66
|
+
export interface DiagnosticSuspiciousTable {
|
|
67
|
+
table: string;
|
|
68
|
+
reason: string;
|
|
69
|
+
}
|
|
70
|
+
export interface DiagnosticSuspiciousUser {
|
|
71
|
+
user: string;
|
|
72
|
+
clientHost?: string;
|
|
73
|
+
reason: string;
|
|
74
|
+
}
|
|
75
|
+
export interface DiagnosticSuspiciousEntities {
|
|
76
|
+
sqls?: DiagnosticSuspiciousSql[];
|
|
77
|
+
sessions?: DiagnosticSuspiciousSession[];
|
|
78
|
+
tables?: DiagnosticSuspiciousTable[];
|
|
79
|
+
users?: DiagnosticSuspiciousUser[];
|
|
80
|
+
}
|
|
81
|
+
export interface DiagnosticEvidenceItem {
|
|
82
|
+
source: string;
|
|
83
|
+
title: string;
|
|
84
|
+
summary: string;
|
|
85
|
+
rawRef?: string;
|
|
86
|
+
}
|
|
87
|
+
export interface TopSlowSqlItem {
|
|
88
|
+
sqlHash?: string;
|
|
89
|
+
digestText?: string;
|
|
90
|
+
sampleSql?: string;
|
|
91
|
+
avgLatencyMs?: number;
|
|
92
|
+
totalLatencyMs?: number;
|
|
93
|
+
execCount?: number;
|
|
94
|
+
avgLockTimeMs?: number;
|
|
95
|
+
avgRowsExamined?: number;
|
|
96
|
+
evidenceSources: string[];
|
|
97
|
+
recommendation?: string;
|
|
98
|
+
}
|
|
99
|
+
export interface DiagnosticNextToolInput {
|
|
100
|
+
tool: DiagnosticToolName | "show_processlist";
|
|
101
|
+
input: Record<string, unknown>;
|
|
102
|
+
rationale: string;
|
|
103
|
+
}
|
|
104
|
+
export type ServiceLatencySuspectedCategory = "slow_sql" | "lock_contention" | "connection_spike" | "resource_pressure" | "mixed";
|
|
105
|
+
export interface ServiceLatencyCandidate {
|
|
106
|
+
type: "sql" | "session" | "table";
|
|
107
|
+
title: string;
|
|
108
|
+
confidence: DiagnosticConfidence;
|
|
109
|
+
sqlHash?: string;
|
|
110
|
+
digestText?: string;
|
|
111
|
+
sampleSql?: string;
|
|
112
|
+
sessionId?: string;
|
|
113
|
+
table?: string;
|
|
114
|
+
rationale: string;
|
|
115
|
+
}
|
|
116
|
+
export interface DbHotspotItem {
|
|
117
|
+
type: "sql" | "session" | "table";
|
|
118
|
+
title: string;
|
|
119
|
+
confidence: DiagnosticConfidence;
|
|
120
|
+
sqlHash?: string;
|
|
121
|
+
digestText?: string;
|
|
122
|
+
sampleSql?: string;
|
|
123
|
+
sessionId?: string;
|
|
124
|
+
table?: string;
|
|
125
|
+
rationale: string;
|
|
126
|
+
evidenceSources: string[];
|
|
127
|
+
recommendation?: string;
|
|
128
|
+
}
|
|
129
|
+
export interface DiagnosticResult {
|
|
130
|
+
tool: DiagnosticToolName;
|
|
131
|
+
status: DiagnosticStatus;
|
|
132
|
+
severity: DiagnosticSeverity;
|
|
133
|
+
summary: string;
|
|
134
|
+
diagnosisWindow: DiagnosisWindow;
|
|
135
|
+
rootCauseCandidates: DiagnosticRootCauseCandidate[];
|
|
136
|
+
keyFindings: string[];
|
|
137
|
+
suspiciousEntities?: DiagnosticSuspiciousEntities;
|
|
138
|
+
evidence: DiagnosticEvidenceItem[];
|
|
139
|
+
recommendedActions: string[];
|
|
140
|
+
recommendedNextTools?: string[];
|
|
141
|
+
nextToolInputs?: DiagnosticNextToolInput[];
|
|
142
|
+
limitations?: string[];
|
|
143
|
+
}
|
|
144
|
+
export interface ServiceLatencyResult {
|
|
145
|
+
tool: "diagnose_service_latency";
|
|
146
|
+
status: DiagnosticStatus;
|
|
147
|
+
summary: string;
|
|
148
|
+
diagnosisWindow: DiagnosisWindow;
|
|
149
|
+
suspectedCategory: ServiceLatencySuspectedCategory;
|
|
150
|
+
topCandidates: ServiceLatencyCandidate[];
|
|
151
|
+
evidence: DiagnosticEvidenceItem[];
|
|
152
|
+
recommendedNextTools: string[];
|
|
153
|
+
nextToolInputs: DiagnosticNextToolInput[];
|
|
154
|
+
limitations?: string[];
|
|
155
|
+
}
|
|
156
|
+
export interface DbHotspotResult {
|
|
157
|
+
tool: "diagnose_db_hotspot";
|
|
158
|
+
status: DiagnosticStatus;
|
|
159
|
+
summary: string;
|
|
160
|
+
diagnosisWindow: DiagnosisWindow;
|
|
161
|
+
scope: "sql" | "table" | "session" | "all";
|
|
162
|
+
hotspots: DbHotspotItem[];
|
|
163
|
+
evidence: DiagnosticEvidenceItem[];
|
|
164
|
+
recommendedNextTools: string[];
|
|
165
|
+
nextToolInputs: DiagnosticNextToolInput[];
|
|
166
|
+
limitations?: string[];
|
|
167
|
+
}
|
|
168
|
+
export interface FindTopSlowSqlResult {
|
|
169
|
+
tool: "find_top_slow_sql";
|
|
170
|
+
status: DiagnosticStatus;
|
|
171
|
+
summary: string;
|
|
172
|
+
diagnosisWindow: DiagnosisWindow;
|
|
173
|
+
topSqls: TopSlowSqlItem[];
|
|
174
|
+
evidence: DiagnosticEvidenceItem[];
|
|
175
|
+
limitations?: string[];
|
|
176
|
+
}
|
|
177
|
+
export interface PlaceholderDiagnosticOptions {
|
|
178
|
+
summary: string;
|
|
179
|
+
candidateTitle: string;
|
|
180
|
+
candidateRationale: string;
|
|
181
|
+
keyFindings?: string[];
|
|
182
|
+
suspiciousEntities?: DiagnosticSuspiciousEntities;
|
|
183
|
+
recommendedActions?: string[];
|
|
184
|
+
limitations?: string[];
|
|
185
|
+
evidence?: DiagnosticEvidenceItem[];
|
|
186
|
+
status?: DiagnosticStatus;
|
|
187
|
+
severity?: DiagnosticSeverity;
|
|
188
|
+
}
|
|
189
|
+
export declare function createPlaceholderDiagnosticResult(tool: DiagnosticToolName, input: DiagnosticBaseInput, options: PlaceholderDiagnosticOptions): DiagnosticResult;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export function createPlaceholderDiagnosticResult(tool, input, options) {
|
|
2
|
+
return {
|
|
3
|
+
tool,
|
|
4
|
+
status: options.status ?? "inconclusive",
|
|
5
|
+
severity: options.severity ?? "info",
|
|
6
|
+
summary: options.summary,
|
|
7
|
+
diagnosisWindow: {
|
|
8
|
+
from: input.timeRange?.from,
|
|
9
|
+
to: input.timeRange?.to,
|
|
10
|
+
relative: input.timeRange?.relative,
|
|
11
|
+
},
|
|
12
|
+
rootCauseCandidates: [
|
|
13
|
+
{
|
|
14
|
+
code: `${tool}_pending`,
|
|
15
|
+
title: options.candidateTitle,
|
|
16
|
+
confidence: "low",
|
|
17
|
+
rationale: options.candidateRationale,
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
keyFindings: options.keyFindings ?? [
|
|
21
|
+
"The diagnostic contract is available, but evidence collectors have not been wired yet.",
|
|
22
|
+
"No live control-plane or data-plane evidence was collected in this run.",
|
|
23
|
+
],
|
|
24
|
+
suspiciousEntities: options.suspiciousEntities,
|
|
25
|
+
evidence: options.evidence ?? [
|
|
26
|
+
{
|
|
27
|
+
source: "diagnostics_scaffold",
|
|
28
|
+
title: "Diagnostic scaffold active",
|
|
29
|
+
summary: "Typed inputs, outputs, and engine entrypoints are in place, but collectors and analyzers are pending.",
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
recommendedActions: options.recommendedActions ?? [
|
|
33
|
+
"Implement the required collectors before relying on this tool for production diagnosis.",
|
|
34
|
+
],
|
|
35
|
+
limitations: options.limitations ?? [
|
|
36
|
+
"This diagnostic currently returns a scaffolded result instead of live evidence-backed analysis.",
|
|
37
|
+
],
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SessionContext } from "../../context/session-context.js";
|
|
2
|
+
import type { DiagnoseLockContentionInput } from "../../diagnostics/types.js";
|
|
3
|
+
import type { QueryResult } from "../../executor/sql-executor.js";
|
|
4
|
+
import type { ShowLockWaitsInput, TaurusDBEngine } from "../../engine.js";
|
|
5
|
+
import { type DeadlockSummary, type MetadataLockRow } from "../helpers.js";
|
|
6
|
+
export declare function showLockWaits(engine: TaurusDBEngine, input: ShowLockWaitsInput, ctx: SessionContext): Promise<QueryResult>;
|
|
7
|
+
export declare function findMetadataLockWaits(engine: TaurusDBEngine, input: DiagnoseLockContentionInput, ctx: SessionContext): Promise<MetadataLockRow[]>;
|
|
8
|
+
export declare function findLatestDeadlock(engine: TaurusDBEngine, ctx: SessionContext): Promise<DeadlockSummary | undefined>;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { clampInteger, lockEvidenceRowLimit, parseDeadlockSummary, parseMetadataLockRows, quoteLiteral, } from "../helpers.js";
|
|
2
|
+
export async function showLockWaits(engine, input, ctx) {
|
|
3
|
+
const maxRows = clampInteger(input.maxRows, 20, 1, 100);
|
|
4
|
+
const includeSql = input.includeSql === true;
|
|
5
|
+
const sqlMaxChars = clampInteger(input.sqlMaxChars, 256, 32, 2048);
|
|
6
|
+
const selectedColumns = [
|
|
7
|
+
"CAST(waiting_thread.PROCESSLIST_ID AS CHAR) AS waiting_session_id",
|
|
8
|
+
"waiting_thread.PROCESSLIST_USER AS waiting_user",
|
|
9
|
+
"waiting_thread.PROCESSLIST_STATE AS waiting_state",
|
|
10
|
+
"waiting_trx.TRX_STATE AS waiting_trx_state",
|
|
11
|
+
"TIMESTAMPDIFF(SECOND, waiting_trx.TRX_WAIT_STARTED, CURRENT_TIMESTAMP) AS wait_age_seconds",
|
|
12
|
+
"CAST(blocking_thread.PROCESSLIST_ID AS CHAR) AS blocking_session_id",
|
|
13
|
+
"blocking_thread.PROCESSLIST_USER AS blocking_user",
|
|
14
|
+
"blocking_thread.PROCESSLIST_STATE AS blocking_state",
|
|
15
|
+
"blocking_trx.TRX_STATE AS blocking_trx_state",
|
|
16
|
+
"TIMESTAMPDIFF(SECOND, blocking_trx.TRX_STARTED, CURRENT_TIMESTAMP) AS blocking_trx_age_seconds",
|
|
17
|
+
"requesting_lock.OBJECT_SCHEMA AS locked_schema",
|
|
18
|
+
"requesting_lock.OBJECT_NAME AS locked_table",
|
|
19
|
+
"requesting_lock.INDEX_NAME AS locked_index",
|
|
20
|
+
"requesting_lock.LOCK_TYPE AS waiting_lock_type",
|
|
21
|
+
"requesting_lock.LOCK_MODE AS waiting_lock_mode",
|
|
22
|
+
"blocking_lock.LOCK_TYPE AS blocking_lock_type",
|
|
23
|
+
"blocking_lock.LOCK_MODE AS blocking_lock_mode",
|
|
24
|
+
];
|
|
25
|
+
if (includeSql) {
|
|
26
|
+
selectedColumns.push("waiting_thread.PROCESSLIST_INFO AS waiting_query", "blocking_thread.PROCESSLIST_INFO AS blocking_query");
|
|
27
|
+
}
|
|
28
|
+
const whereClauses = ["waits.ENGINE = 'INNODB'"];
|
|
29
|
+
const targetSchema = ctx.database;
|
|
30
|
+
if (targetSchema) {
|
|
31
|
+
whereClauses.push(`requesting_lock.OBJECT_SCHEMA = ${quoteLiteral(targetSchema)}`);
|
|
32
|
+
}
|
|
33
|
+
if (input.table) {
|
|
34
|
+
whereClauses.push(`requesting_lock.OBJECT_NAME = ${quoteLiteral(input.table)}`);
|
|
35
|
+
}
|
|
36
|
+
if (input.blockerSessionId) {
|
|
37
|
+
whereClauses.push(`CAST(blocking_thread.PROCESSLIST_ID AS CHAR) = ${quoteLiteral(input.blockerSessionId)}`);
|
|
38
|
+
}
|
|
39
|
+
const sql = `
|
|
40
|
+
SELECT ${selectedColumns.join(", ")}
|
|
41
|
+
FROM performance_schema.data_lock_waits AS waits
|
|
42
|
+
INNER JOIN performance_schema.data_locks AS requesting_lock
|
|
43
|
+
ON requesting_lock.ENGINE = waits.ENGINE
|
|
44
|
+
AND requesting_lock.ENGINE_LOCK_ID = waits.REQUESTING_ENGINE_LOCK_ID
|
|
45
|
+
INNER JOIN performance_schema.data_locks AS blocking_lock
|
|
46
|
+
ON blocking_lock.ENGINE = waits.ENGINE
|
|
47
|
+
AND blocking_lock.ENGINE_LOCK_ID = waits.BLOCKING_ENGINE_LOCK_ID
|
|
48
|
+
LEFT JOIN information_schema.INNODB_TRX AS waiting_trx
|
|
49
|
+
ON waiting_trx.TRX_ID = waits.REQUESTING_ENGINE_TRANSACTION_ID
|
|
50
|
+
LEFT JOIN information_schema.INNODB_TRX AS blocking_trx
|
|
51
|
+
ON blocking_trx.TRX_ID = waits.BLOCKING_ENGINE_TRANSACTION_ID
|
|
52
|
+
LEFT JOIN performance_schema.threads AS waiting_thread
|
|
53
|
+
ON waiting_thread.THREAD_ID = waits.REQUESTING_THREAD_ID
|
|
54
|
+
LEFT JOIN performance_schema.threads AS blocking_thread
|
|
55
|
+
ON blocking_thread.THREAD_ID = waits.BLOCKING_THREAD_ID
|
|
56
|
+
WHERE ${whereClauses.join(" AND ")}
|
|
57
|
+
ORDER BY wait_age_seconds DESC, blocking_trx_age_seconds DESC, blocking_session_id DESC
|
|
58
|
+
LIMIT ${maxRows}
|
|
59
|
+
`.trim();
|
|
60
|
+
return engine.executor.executeReadonly(sql, ctx, {
|
|
61
|
+
maxRows,
|
|
62
|
+
maxColumns: selectedColumns.length,
|
|
63
|
+
maxFieldChars: includeSql ? sqlMaxChars : 256,
|
|
64
|
+
timeoutMs: ctx.limits.timeoutMs,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
export async function findMetadataLockWaits(engine, input, ctx) {
|
|
68
|
+
const maxRows = lockEvidenceRowLimit(input.evidenceLevel);
|
|
69
|
+
const whereClauses = [
|
|
70
|
+
"waiting.LOCK_STATUS = 'PENDING'",
|
|
71
|
+
"blocking.LOCK_STATUS = 'GRANTED'",
|
|
72
|
+
"waiting.OWNER_THREAD_ID <> blocking.OWNER_THREAD_ID",
|
|
73
|
+
];
|
|
74
|
+
const focusedTable = input.table?.includes(".")
|
|
75
|
+
? {
|
|
76
|
+
schema: input.table.split(".")[0],
|
|
77
|
+
table: input.table.split(".").slice(1).join("."),
|
|
78
|
+
}
|
|
79
|
+
: {
|
|
80
|
+
schema: ctx.database,
|
|
81
|
+
table: input.table,
|
|
82
|
+
};
|
|
83
|
+
if (focusedTable.schema) {
|
|
84
|
+
whereClauses.push(`waiting.OBJECT_SCHEMA = ${quoteLiteral(focusedTable.schema)}`);
|
|
85
|
+
}
|
|
86
|
+
if (focusedTable.table) {
|
|
87
|
+
whereClauses.push(`waiting.OBJECT_NAME = ${quoteLiteral(focusedTable.table)}`);
|
|
88
|
+
}
|
|
89
|
+
if (input.blockerSessionId) {
|
|
90
|
+
whereClauses.push(`blocking_threads.PROCESSLIST_ID = ${quoteLiteral(input.blockerSessionId)}`);
|
|
91
|
+
}
|
|
92
|
+
const sql = `
|
|
93
|
+
SELECT
|
|
94
|
+
waiting_threads.PROCESSLIST_ID AS waiting_session_id,
|
|
95
|
+
waiting_threads.PROCESSLIST_USER AS waiting_user,
|
|
96
|
+
waiting_threads.PROCESSLIST_STATE AS waiting_state,
|
|
97
|
+
blocking_threads.PROCESSLIST_ID AS blocking_session_id,
|
|
98
|
+
blocking_threads.PROCESSLIST_USER AS blocking_user,
|
|
99
|
+
blocking_threads.PROCESSLIST_STATE AS blocking_state,
|
|
100
|
+
waiting.OBJECT_TYPE AS object_type,
|
|
101
|
+
waiting.OBJECT_SCHEMA AS object_schema,
|
|
102
|
+
waiting.OBJECT_NAME AS object_name,
|
|
103
|
+
waiting.LOCK_TYPE AS waiting_lock_type,
|
|
104
|
+
waiting.LOCK_DURATION AS waiting_lock_duration,
|
|
105
|
+
blocking.LOCK_TYPE AS blocking_lock_type,
|
|
106
|
+
blocking.LOCK_DURATION AS blocking_lock_duration
|
|
107
|
+
FROM performance_schema.metadata_locks AS waiting
|
|
108
|
+
INNER JOIN performance_schema.threads AS waiting_threads
|
|
109
|
+
ON waiting_threads.THREAD_ID = waiting.OWNER_THREAD_ID
|
|
110
|
+
INNER JOIN performance_schema.metadata_locks AS blocking
|
|
111
|
+
ON blocking.OBJECT_TYPE = waiting.OBJECT_TYPE
|
|
112
|
+
AND COALESCE(blocking.OBJECT_SCHEMA, '') = COALESCE(waiting.OBJECT_SCHEMA, '')
|
|
113
|
+
AND COALESCE(blocking.OBJECT_NAME, '') = COALESCE(waiting.OBJECT_NAME, '')
|
|
114
|
+
INNER JOIN performance_schema.threads AS blocking_threads
|
|
115
|
+
ON blocking_threads.THREAD_ID = blocking.OWNER_THREAD_ID
|
|
116
|
+
WHERE ${whereClauses.join(" AND ")}
|
|
117
|
+
ORDER BY waiting.OBJECT_SCHEMA ASC, waiting.OBJECT_NAME ASC, blocking_threads.PROCESSLIST_ID ASC
|
|
118
|
+
LIMIT ${maxRows}
|
|
119
|
+
`.trim();
|
|
120
|
+
try {
|
|
121
|
+
const result = await engine.executor.executeReadonly(sql, ctx, {
|
|
122
|
+
maxRows,
|
|
123
|
+
maxColumns: 13,
|
|
124
|
+
maxFieldChars: 512,
|
|
125
|
+
timeoutMs: ctx.limits.timeoutMs,
|
|
126
|
+
});
|
|
127
|
+
return parseMetadataLockRows(result);
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return [];
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
export async function findLatestDeadlock(engine, ctx) {
|
|
134
|
+
try {
|
|
135
|
+
const result = await engine.executor.executeReadonly("SHOW ENGINE INNODB STATUS", ctx, {
|
|
136
|
+
maxRows: 1,
|
|
137
|
+
maxColumns: 3,
|
|
138
|
+
maxFieldChars: 32768,
|
|
139
|
+
timeoutMs: ctx.limits.timeoutMs,
|
|
140
|
+
});
|
|
141
|
+
return parseDeadlockSummary(result);
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { SessionContext } from "../../context/session-context.js";
|
|
2
|
+
import type { QueryResult } from "../../executor/sql-executor.js";
|
|
3
|
+
import type { ShowProcesslistInput, TaurusDBEngine } from "../../engine.js";
|
|
4
|
+
export declare function showProcesslist(engine: TaurusDBEngine, input: ShowProcesslistInput, ctx: SessionContext): Promise<QueryResult>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { clampInteger, escapeLikePrefix, quoteLiteral, } from "../helpers.js";
|
|
2
|
+
export async function showProcesslist(engine, input, ctx) {
|
|
3
|
+
const maxRows = clampInteger(input.maxRows, 20, 1, 100);
|
|
4
|
+
const minTimeSeconds = clampInteger(input.minTimeSeconds, 0, 0, 86_400);
|
|
5
|
+
const includeIdle = input.includeIdle === true;
|
|
6
|
+
const includeSystem = input.includeSystem === true;
|
|
7
|
+
const includeInfo = input.includeInfo === true;
|
|
8
|
+
const infoMaxChars = clampInteger(input.infoMaxChars, 256, 32, 2048);
|
|
9
|
+
const selectedColumns = [
|
|
10
|
+
"ID AS session_id",
|
|
11
|
+
"USER AS user",
|
|
12
|
+
"HOST AS host",
|
|
13
|
+
"DB AS database_name",
|
|
14
|
+
"COMMAND AS command",
|
|
15
|
+
"TIME AS time_seconds",
|
|
16
|
+
"STATE AS state",
|
|
17
|
+
];
|
|
18
|
+
if (includeInfo) {
|
|
19
|
+
selectedColumns.push("INFO AS info_preview");
|
|
20
|
+
}
|
|
21
|
+
const whereClauses = [];
|
|
22
|
+
if (!includeIdle) {
|
|
23
|
+
whereClauses.push("COMMAND <> 'Sleep'");
|
|
24
|
+
}
|
|
25
|
+
if (!includeSystem) {
|
|
26
|
+
whereClauses.push("USER <> 'system user'");
|
|
27
|
+
}
|
|
28
|
+
if (input.user) {
|
|
29
|
+
whereClauses.push(`USER = ${quoteLiteral(input.user)}`);
|
|
30
|
+
}
|
|
31
|
+
if (input.host) {
|
|
32
|
+
whereClauses.push(`HOST LIKE ${quoteLiteral(`${escapeLikePrefix(input.host)}%`)} ESCAPE '\\'`);
|
|
33
|
+
}
|
|
34
|
+
if (input.sessionDatabase) {
|
|
35
|
+
whereClauses.push(`DB = ${quoteLiteral(input.sessionDatabase)}`);
|
|
36
|
+
}
|
|
37
|
+
if (input.command) {
|
|
38
|
+
whereClauses.push(`COMMAND = ${quoteLiteral(input.command)}`);
|
|
39
|
+
}
|
|
40
|
+
if (minTimeSeconds > 0) {
|
|
41
|
+
whereClauses.push(`TIME >= ${minTimeSeconds}`);
|
|
42
|
+
}
|
|
43
|
+
const sql = `
|
|
44
|
+
SELECT ${selectedColumns.join(", ")}
|
|
45
|
+
FROM information_schema.PROCESSLIST
|
|
46
|
+
${whereClauses.length > 0 ? `WHERE ${whereClauses.join(" AND ")}` : ""}
|
|
47
|
+
ORDER BY TIME DESC, ID DESC
|
|
48
|
+
LIMIT ${maxRows}
|
|
49
|
+
`.trim();
|
|
50
|
+
return engine.executor.executeReadonly(sql, ctx, {
|
|
51
|
+
maxRows,
|
|
52
|
+
maxColumns: selectedColumns.length,
|
|
53
|
+
maxFieldChars: includeInfo ? infoMaxChars : 256,
|
|
54
|
+
timeoutMs: ctx.limits.timeoutMs,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { SessionContext } from "../../context/session-context.js";
|
|
2
|
+
import type { FindTopSlowSqlInput } from "../../diagnostics/types.js";
|
|
3
|
+
import type { TaurusDBEngine } from "../../engine.js";
|
|
4
|
+
import { type StatementDigestRow, type StatementWaitEventRow } from "../helpers.js";
|
|
5
|
+
export declare function findStatementDigestSample(engine: TaurusDBEngine, digestText: string, ctx: SessionContext): Promise<StatementDigestRow | undefined>;
|
|
6
|
+
export declare function findStatementDigestSampleForSql(engine: TaurusDBEngine, sql: string, ctx: SessionContext): Promise<StatementDigestRow | undefined>;
|
|
7
|
+
export declare function findStatementDigestCandidatesForSqlHints(engine: TaurusDBEngine, sqlText: string, ctx: SessionContext): Promise<StatementDigestRow[]>;
|
|
8
|
+
export declare function findTopStatementDigests(engine: TaurusDBEngine, input: FindTopSlowSqlInput, ctx: SessionContext): Promise<StatementDigestRow[]>;
|
|
9
|
+
export declare function isPerformanceSchemaEnabled(engine: TaurusDBEngine, ctx: SessionContext): Promise<boolean | undefined>;
|
|
10
|
+
export declare function findStatementWaitEvents(engine: TaurusDBEngine, digestText: string, ctx: SessionContext): Promise<StatementWaitEventRow[]>;
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { clampInteger, digestMatchScore, escapeLikePrefix, extractSqlTableNameHints, parseStatementDigestRows, parseStatementWaitEventRows, quoteLiteral, topSlowSqlOrderBy, } from "../helpers.js";
|
|
2
|
+
export async function findStatementDigestSample(engine, digestText, ctx) {
|
|
3
|
+
const whereClauses = [`DIGEST_TEXT = ${quoteLiteral(digestText)}`];
|
|
4
|
+
if (ctx.database) {
|
|
5
|
+
whereClauses.push(`SCHEMA_NAME = ${quoteLiteral(ctx.database)}`);
|
|
6
|
+
}
|
|
7
|
+
const sql = `
|
|
8
|
+
SELECT
|
|
9
|
+
SCHEMA_NAME AS schema_name,
|
|
10
|
+
DIGEST AS digest,
|
|
11
|
+
DIGEST_TEXT AS digest_text,
|
|
12
|
+
QUERY_SAMPLE_TEXT AS query_sample_text,
|
|
13
|
+
COUNT_STAR AS exec_count,
|
|
14
|
+
ROUND(AVG_TIMER_WAIT / 1000000000, 3) AS avg_latency_ms,
|
|
15
|
+
ROUND(SUM_TIMER_WAIT / 1000000000, 3) AS total_latency_ms,
|
|
16
|
+
ROUND(MAX_TIMER_WAIT / 1000000000, 3) AS max_latency_ms,
|
|
17
|
+
ROUND(SUM_LOCK_TIME / 1000000000 / NULLIF(COUNT_STAR, 0), 3) AS avg_lock_time_ms,
|
|
18
|
+
ROUND(SUM_ROWS_EXAMINED / NULLIF(COUNT_STAR, 0), 3) AS avg_rows_examined,
|
|
19
|
+
ROUND(SUM_SORT_ROWS / NULLIF(COUNT_STAR, 0), 3) AS avg_sort_rows,
|
|
20
|
+
ROUND(SUM_CREATED_TMP_TABLES / NULLIF(COUNT_STAR, 0), 3) AS avg_tmp_tables,
|
|
21
|
+
ROUND(SUM_CREATED_TMP_DISK_TABLES / NULLIF(COUNT_STAR, 0), 3) AS avg_tmp_disk_tables,
|
|
22
|
+
SUM_SELECT_SCAN AS select_scan_count,
|
|
23
|
+
SUM_NO_INDEX_USED AS no_index_used_count
|
|
24
|
+
FROM performance_schema.events_statements_summary_by_digest
|
|
25
|
+
WHERE ${whereClauses.join(" AND ")}
|
|
26
|
+
ORDER BY SUM_TIMER_WAIT DESC, COUNT_STAR DESC
|
|
27
|
+
LIMIT 1
|
|
28
|
+
`.trim();
|
|
29
|
+
const result = await engine.executor.executeReadonly(sql, ctx, {
|
|
30
|
+
maxRows: 1,
|
|
31
|
+
maxColumns: 15,
|
|
32
|
+
maxFieldChars: 2048,
|
|
33
|
+
timeoutMs: ctx.limits.timeoutMs,
|
|
34
|
+
});
|
|
35
|
+
return parseStatementDigestRows(result)[0];
|
|
36
|
+
}
|
|
37
|
+
export async function findStatementDigestSampleForSql(engine, sql, ctx) {
|
|
38
|
+
const candidates = await engine.findTopStatementDigests({
|
|
39
|
+
database: ctx.database,
|
|
40
|
+
topN: 20,
|
|
41
|
+
sortBy: "total_latency",
|
|
42
|
+
}, ctx);
|
|
43
|
+
const ranked = candidates
|
|
44
|
+
.map((candidate) => ({
|
|
45
|
+
candidate,
|
|
46
|
+
score: digestMatchScore(sql, candidate),
|
|
47
|
+
}))
|
|
48
|
+
.filter((item) => item.score > 0)
|
|
49
|
+
.sort((left, right) => right.score - left.score ||
|
|
50
|
+
(right.candidate.totalLatencyMs ?? 0) -
|
|
51
|
+
(left.candidate.totalLatencyMs ?? 0) ||
|
|
52
|
+
(right.candidate.execCount ?? 0) - (left.candidate.execCount ?? 0));
|
|
53
|
+
if (ranked[0]?.candidate) {
|
|
54
|
+
return ranked[0].candidate;
|
|
55
|
+
}
|
|
56
|
+
const hintCandidates = await engine.findStatementDigestCandidatesForSqlHints(sql, ctx).catch(() => []);
|
|
57
|
+
return hintCandidates
|
|
58
|
+
.map((candidate) => ({
|
|
59
|
+
candidate,
|
|
60
|
+
score: digestMatchScore(sql, candidate),
|
|
61
|
+
}))
|
|
62
|
+
.filter((item) => item.score > 0)
|
|
63
|
+
.sort((left, right) => right.score - left.score ||
|
|
64
|
+
(right.candidate.totalLatencyMs ?? 0) -
|
|
65
|
+
(left.candidate.totalLatencyMs ?? 0) ||
|
|
66
|
+
(right.candidate.execCount ?? 0) - (left.candidate.execCount ?? 0))[0]?.candidate;
|
|
67
|
+
}
|
|
68
|
+
export async function findStatementDigestCandidatesForSqlHints(engine, sqlText, ctx) {
|
|
69
|
+
const tableHints = extractSqlTableNameHints(sqlText).slice(0, 3);
|
|
70
|
+
if (tableHints.length === 0) {
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
const whereClauses = ["DIGEST_TEXT IS NOT NULL", "DIGEST_TEXT <> 'NULL'"];
|
|
74
|
+
if (ctx.database) {
|
|
75
|
+
whereClauses.push(`SCHEMA_NAME = ${quoteLiteral(ctx.database)}`);
|
|
76
|
+
}
|
|
77
|
+
const tableClauses = tableHints.map((table) => {
|
|
78
|
+
const tableLike = quoteLiteral(`%${escapeLikePrefix(table)}%`);
|
|
79
|
+
return `(DIGEST_TEXT LIKE ${tableLike} ESCAPE '\\\\' OR QUERY_SAMPLE_TEXT LIKE ${tableLike} ESCAPE '\\\\')`;
|
|
80
|
+
});
|
|
81
|
+
whereClauses.push(`(${tableClauses.join(" OR ")})`);
|
|
82
|
+
const sql = `
|
|
83
|
+
SELECT
|
|
84
|
+
SCHEMA_NAME AS schema_name,
|
|
85
|
+
DIGEST AS digest,
|
|
86
|
+
DIGEST_TEXT AS digest_text,
|
|
87
|
+
QUERY_SAMPLE_TEXT AS query_sample_text,
|
|
88
|
+
COUNT_STAR AS exec_count,
|
|
89
|
+
ROUND(AVG_TIMER_WAIT / 1000000000, 3) AS avg_latency_ms,
|
|
90
|
+
ROUND(SUM_TIMER_WAIT / 1000000000, 3) AS total_latency_ms,
|
|
91
|
+
ROUND(MAX_TIMER_WAIT / 1000000000, 3) AS max_latency_ms,
|
|
92
|
+
ROUND(SUM_LOCK_TIME / 1000000000 / NULLIF(COUNT_STAR, 0), 3) AS avg_lock_time_ms,
|
|
93
|
+
ROUND(SUM_ROWS_EXAMINED / NULLIF(COUNT_STAR, 0), 3) AS avg_rows_examined,
|
|
94
|
+
ROUND(SUM_SORT_ROWS / NULLIF(COUNT_STAR, 0), 3) AS avg_sort_rows,
|
|
95
|
+
ROUND(SUM_CREATED_TMP_TABLES / NULLIF(COUNT_STAR, 0), 3) AS avg_tmp_tables,
|
|
96
|
+
ROUND(SUM_CREATED_TMP_DISK_TABLES / NULLIF(COUNT_STAR, 0), 3) AS avg_tmp_disk_tables,
|
|
97
|
+
SUM_SELECT_SCAN AS select_scan_count,
|
|
98
|
+
SUM_NO_INDEX_USED AS no_index_used_count
|
|
99
|
+
FROM performance_schema.events_statements_summary_by_digest
|
|
100
|
+
WHERE ${whereClauses.join(" AND ")}
|
|
101
|
+
ORDER BY SUM_TIMER_WAIT DESC, AVG_TIMER_WAIT DESC, COUNT_STAR DESC
|
|
102
|
+
LIMIT 50
|
|
103
|
+
`.trim();
|
|
104
|
+
const result = await engine.executor.executeReadonly(sql, ctx, {
|
|
105
|
+
maxRows: 50,
|
|
106
|
+
maxColumns: 15,
|
|
107
|
+
maxFieldChars: 4096,
|
|
108
|
+
timeoutMs: ctx.limits.timeoutMs,
|
|
109
|
+
});
|
|
110
|
+
return parseStatementDigestRows(result);
|
|
111
|
+
}
|
|
112
|
+
export async function findTopStatementDigests(engine, input, ctx) {
|
|
113
|
+
const maxRows = clampInteger(input.topN, 5, 1, 20);
|
|
114
|
+
const whereClauses = ["DIGEST_TEXT IS NOT NULL", "DIGEST_TEXT <> 'NULL'"];
|
|
115
|
+
if (ctx.database) {
|
|
116
|
+
whereClauses.push(`SCHEMA_NAME = ${quoteLiteral(ctx.database)}`);
|
|
117
|
+
}
|
|
118
|
+
const sql = `
|
|
119
|
+
SELECT
|
|
120
|
+
SCHEMA_NAME AS schema_name,
|
|
121
|
+
DIGEST AS digest,
|
|
122
|
+
DIGEST_TEXT AS digest_text,
|
|
123
|
+
QUERY_SAMPLE_TEXT AS query_sample_text,
|
|
124
|
+
COUNT_STAR AS exec_count,
|
|
125
|
+
ROUND(AVG_TIMER_WAIT / 1000000000, 3) AS avg_latency_ms,
|
|
126
|
+
ROUND(SUM_TIMER_WAIT / 1000000000, 3) AS total_latency_ms,
|
|
127
|
+
ROUND(MAX_TIMER_WAIT / 1000000000, 3) AS max_latency_ms,
|
|
128
|
+
ROUND(SUM_LOCK_TIME / 1000000000 / NULLIF(COUNT_STAR, 0), 3) AS avg_lock_time_ms,
|
|
129
|
+
ROUND(SUM_ROWS_EXAMINED / NULLIF(COUNT_STAR, 0), 3) AS avg_rows_examined,
|
|
130
|
+
ROUND(SUM_SORT_ROWS / NULLIF(COUNT_STAR, 0), 3) AS avg_sort_rows,
|
|
131
|
+
ROUND(SUM_CREATED_TMP_TABLES / NULLIF(COUNT_STAR, 0), 3) AS avg_tmp_tables,
|
|
132
|
+
ROUND(SUM_CREATED_TMP_DISK_TABLES / NULLIF(COUNT_STAR, 0), 3) AS avg_tmp_disk_tables,
|
|
133
|
+
SUM_SELECT_SCAN AS select_scan_count,
|
|
134
|
+
SUM_NO_INDEX_USED AS no_index_used_count
|
|
135
|
+
FROM performance_schema.events_statements_summary_by_digest
|
|
136
|
+
WHERE ${whereClauses.join(" AND ")}
|
|
137
|
+
ORDER BY ${topSlowSqlOrderBy(input.sortBy)}
|
|
138
|
+
LIMIT ${maxRows}
|
|
139
|
+
`.trim();
|
|
140
|
+
const result = await engine.executor.executeReadonly(sql, ctx, {
|
|
141
|
+
maxRows,
|
|
142
|
+
maxColumns: 15,
|
|
143
|
+
maxFieldChars: 4096,
|
|
144
|
+
timeoutMs: ctx.limits.timeoutMs,
|
|
145
|
+
});
|
|
146
|
+
return parseStatementDigestRows(result);
|
|
147
|
+
}
|
|
148
|
+
export async function isPerformanceSchemaEnabled(engine, ctx) {
|
|
149
|
+
try {
|
|
150
|
+
const result = await engine.executor.executeReadonly("SELECT @@performance_schema AS performance_schema_enabled", ctx, {
|
|
151
|
+
maxRows: 1,
|
|
152
|
+
maxColumns: 1,
|
|
153
|
+
maxFieldChars: 64,
|
|
154
|
+
timeoutMs: ctx.limits.timeoutMs,
|
|
155
|
+
});
|
|
156
|
+
const value = result.rows?.[0]?.[0];
|
|
157
|
+
if (typeof value === "number") {
|
|
158
|
+
return value === 1;
|
|
159
|
+
}
|
|
160
|
+
if (typeof value === "string") {
|
|
161
|
+
return value === "1" || value.toLowerCase() === "on";
|
|
162
|
+
}
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
return undefined;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
export async function findStatementWaitEvents(engine, digestText, ctx) {
|
|
170
|
+
const whereClauses = [`stmt.DIGEST_TEXT = ${quoteLiteral(digestText)}`];
|
|
171
|
+
if (ctx.database) {
|
|
172
|
+
whereClauses.push(`stmt.CURRENT_SCHEMA = ${quoteLiteral(ctx.database)}`);
|
|
173
|
+
}
|
|
174
|
+
const sql = `
|
|
175
|
+
SELECT
|
|
176
|
+
waits.EVENT_NAME AS event_name,
|
|
177
|
+
COUNT(*) AS sample_count,
|
|
178
|
+
COUNT(DISTINCT CONCAT(stmt.THREAD_ID, ':', stmt.EVENT_ID)) AS statement_count,
|
|
179
|
+
ROUND(SUM(waits.TIMER_WAIT) / 1000000000, 3) AS total_wait_ms,
|
|
180
|
+
ROUND(AVG(waits.TIMER_WAIT) / 1000000000, 3) AS avg_wait_ms
|
|
181
|
+
FROM performance_schema.events_statements_history_long AS stmt
|
|
182
|
+
INNER JOIN performance_schema.events_waits_history_long AS waits
|
|
183
|
+
ON waits.THREAD_ID = stmt.THREAD_ID
|
|
184
|
+
AND waits.NESTING_EVENT_ID = stmt.EVENT_ID
|
|
185
|
+
AND waits.NESTING_EVENT_TYPE = 'STATEMENT'
|
|
186
|
+
WHERE ${whereClauses.join(" AND ")}
|
|
187
|
+
GROUP BY waits.EVENT_NAME
|
|
188
|
+
ORDER BY total_wait_ms DESC, sample_count DESC, event_name ASC
|
|
189
|
+
LIMIT 3
|
|
190
|
+
`.trim();
|
|
191
|
+
try {
|
|
192
|
+
const result = await engine.executor.executeReadonly(sql, ctx, {
|
|
193
|
+
maxRows: 3,
|
|
194
|
+
maxColumns: 5,
|
|
195
|
+
maxFieldChars: 256,
|
|
196
|
+
timeoutMs: ctx.limits.timeoutMs,
|
|
197
|
+
});
|
|
198
|
+
return parseStatementWaitEventRows(result);
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
return [];
|
|
202
|
+
}
|
|
203
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { SessionContext } from "../../context/session-context.js";
|
|
2
|
+
import type { DiagnoseStoragePressureInput } from "../../diagnostics/types.js";
|
|
3
|
+
import type { TaurusDBEngine } from "../../engine.js";
|
|
4
|
+
import { type StatementDigestRow, type TableStorageRow } from "../helpers.js";
|
|
5
|
+
export declare function findStorageStatementDigests(engine: TaurusDBEngine, input: DiagnoseStoragePressureInput, ctx: SessionContext): Promise<StatementDigestRow[]>;
|
|
6
|
+
export declare function findTableStorageStats(engine: TaurusDBEngine, input: DiagnoseStoragePressureInput, ctx: SessionContext): Promise<TableStorageRow[]>;
|