forge-sql-orm 2.1.3 → 2.1.5
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 +291 -0
- package/dist/ForgeSQLORM.js +713 -12
- package/dist/ForgeSQLORM.js.map +1 -1
- package/dist/ForgeSQLORM.mjs +716 -15
- package/dist/ForgeSQLORM.mjs.map +1 -1
- package/dist/core/ForgeSQLCrudOperations.d.ts.map +1 -1
- package/dist/core/ForgeSQLORM.d.ts +23 -0
- package/dist/core/ForgeSQLORM.d.ts.map +1 -1
- package/dist/core/ForgeSQLQueryBuilder.d.ts +36 -5
- package/dist/core/ForgeSQLQueryBuilder.d.ts.map +1 -1
- package/dist/core/ForgeSQLSelectOperations.d.ts.map +1 -1
- package/dist/core/SystemTables.d.ts +5039 -0
- package/dist/core/SystemTables.d.ts.map +1 -1
- package/dist/lib/drizzle/extensions/additionalActions.d.ts.map +1 -1
- package/dist/utils/cacheContextUtils.d.ts.map +1 -1
- package/dist/utils/cacheUtils.d.ts.map +1 -1
- package/dist/utils/forgeDriver.d.ts +21 -0
- package/dist/utils/forgeDriver.d.ts.map +1 -1
- package/dist/utils/forgeDriverProxy.d.ts.map +1 -1
- package/dist/utils/metadataContextUtils.d.ts +11 -0
- package/dist/utils/metadataContextUtils.d.ts.map +1 -0
- package/dist/utils/sqlUtils.d.ts.map +1 -1
- package/dist/webtriggers/applyMigrationsWebTrigger.d.ts +1 -1
- package/dist/webtriggers/applyMigrationsWebTrigger.d.ts.map +1 -1
- package/dist/webtriggers/clearCacheSchedulerTrigger.d.ts.map +1 -1
- package/dist/webtriggers/dropMigrationWebTrigger.d.ts.map +1 -1
- package/dist/webtriggers/dropTablesMigrationWebTrigger.d.ts.map +1 -1
- package/dist/webtriggers/fetchSchemaWebTrigger.d.ts.map +1 -1
- package/dist/webtriggers/index.d.ts +1 -0
- package/dist/webtriggers/index.d.ts.map +1 -1
- package/dist/webtriggers/topSlowestStatementLastHourTrigger.d.ts +89 -0
- package/dist/webtriggers/topSlowestStatementLastHourTrigger.d.ts.map +1 -0
- package/package.json +4 -3
- package/src/core/ForgeSQLCrudOperations.ts +3 -0
- package/src/core/ForgeSQLORM.ts +119 -51
- package/src/core/ForgeSQLQueryBuilder.ts +51 -17
- package/src/core/ForgeSQLSelectOperations.ts +2 -0
- package/src/core/SystemTables.ts +313 -1
- package/src/lib/drizzle/extensions/additionalActions.ts +2 -0
- package/src/utils/cacheContextUtils.ts +4 -2
- package/src/utils/cacheUtils.ts +20 -8
- package/src/utils/forgeDriver.ts +22 -1
- package/src/utils/forgeDriverProxy.ts +2 -0
- package/src/utils/metadataContextUtils.ts +24 -0
- package/src/utils/sqlUtils.ts +1 -0
- package/src/webtriggers/applyMigrationsWebTrigger.ts +10 -5
- package/src/webtriggers/clearCacheSchedulerTrigger.ts +1 -0
- package/src/webtriggers/dropMigrationWebTrigger.ts +2 -0
- package/src/webtriggers/dropTablesMigrationWebTrigger.ts +2 -0
- package/src/webtriggers/fetchSchemaWebTrigger.ts +1 -0
- package/src/webtriggers/index.ts +1 -0
- package/src/webtriggers/topSlowestStatementLastHourTrigger.ts +360 -0
package/dist/ForgeSQLORM.js
CHANGED
|
@@ -410,7 +410,7 @@ async function clearCursorCache(tables, cursor, options) {
|
|
|
410
410
|
entityQueryBuilder = entityQueryBuilder.cursor(cursor);
|
|
411
411
|
}
|
|
412
412
|
const listResult = await entityQueryBuilder.limit(100).getMany();
|
|
413
|
-
if (options.
|
|
413
|
+
if (options.logCache) {
|
|
414
414
|
console.warn(`clear cache Records: ${JSON.stringify(listResult.results.map((r) => r.key))}`);
|
|
415
415
|
}
|
|
416
416
|
await deleteCacheEntriesInBatches(listResult.results, cacheEntityName);
|
|
@@ -431,7 +431,7 @@ async function clearExpirationCursorCache(cursor, options) {
|
|
|
431
431
|
entityQueryBuilder = entityQueryBuilder.cursor(cursor);
|
|
432
432
|
}
|
|
433
433
|
const listResult = await entityQueryBuilder.limit(100).getMany();
|
|
434
|
-
if (options.
|
|
434
|
+
if (options.logCache) {
|
|
435
435
|
console.warn(`clear expired Records: ${JSON.stringify(listResult.results.map((r) => r.key))}`);
|
|
436
436
|
}
|
|
437
437
|
await deleteCacheEntriesInBatches(listResult.results, cacheEntityName);
|
|
@@ -480,7 +480,7 @@ async function clearTablesCache(tables, options) {
|
|
|
480
480
|
"clearing cache"
|
|
481
481
|
);
|
|
482
482
|
} finally {
|
|
483
|
-
if (options.
|
|
483
|
+
if (options.logCache) {
|
|
484
484
|
const duration = luxon.DateTime.now().toSeconds() - startTime.toSeconds();
|
|
485
485
|
console.info(`Cleared ${totalRecords} cache records in ${duration} seconds`);
|
|
486
486
|
}
|
|
@@ -499,7 +499,7 @@ async function clearExpiredCache(options) {
|
|
|
499
499
|
);
|
|
500
500
|
} finally {
|
|
501
501
|
const duration = luxon.DateTime.now().toSeconds() - startTime.toSeconds();
|
|
502
|
-
if (options?.
|
|
502
|
+
if (options?.logCache) {
|
|
503
503
|
console.debug(`Cleared ${totalRecords} expired cache records in ${duration} seconds`);
|
|
504
504
|
}
|
|
505
505
|
}
|
|
@@ -514,7 +514,7 @@ async function getFromCache(query, options) {
|
|
|
514
514
|
const sqlQuery = query.toSQL();
|
|
515
515
|
const key = hashKey(sqlQuery);
|
|
516
516
|
if (await isTableContainsTableInCacheContext(sqlQuery.sql, options)) {
|
|
517
|
-
if (options.
|
|
517
|
+
if (options.logCache) {
|
|
518
518
|
console.warn(`Context contains value to clear. Skip getting from cache`);
|
|
519
519
|
}
|
|
520
520
|
return void 0;
|
|
@@ -522,7 +522,7 @@ async function getFromCache(query, options) {
|
|
|
522
522
|
try {
|
|
523
523
|
const cacheResult = await kvs.kvs.entity(options.cacheEntityName).get(key);
|
|
524
524
|
if (cacheResult && cacheResult[expirationName] >= getCurrentTime() && sqlQuery.sql.toLowerCase() === cacheResult[entityQueryName]) {
|
|
525
|
-
if (options.
|
|
525
|
+
if (options.logCache) {
|
|
526
526
|
console.warn(`Get value from cache, cacheKey: ${key}`);
|
|
527
527
|
}
|
|
528
528
|
const results = cacheResult[dataName];
|
|
@@ -543,7 +543,7 @@ async function setCacheResult(query, options, results, cacheTtl) {
|
|
|
543
543
|
const dataName = options.cacheEntityDataName ?? CACHE_CONSTANTS.DEFAULT_DATA_NAME;
|
|
544
544
|
const sqlQuery = query.toSQL();
|
|
545
545
|
if (await isTableContainsTableInCacheContext(sqlQuery.sql, options)) {
|
|
546
|
-
if (options.
|
|
546
|
+
if (options.logCache) {
|
|
547
547
|
console.warn(`Context contains value to clear. Skip setting from cache`);
|
|
548
548
|
}
|
|
549
549
|
return;
|
|
@@ -558,7 +558,7 @@ async function setCacheResult(query, options, results, cacheTtl) {
|
|
|
558
558
|
},
|
|
559
559
|
{ entityName: options.cacheEntityName }
|
|
560
560
|
).execute();
|
|
561
|
-
if (options.
|
|
561
|
+
if (options.logCache) {
|
|
562
562
|
console.warn(`Store value to cache, cacheKey: ${key}`);
|
|
563
563
|
}
|
|
564
564
|
} catch (error) {
|
|
@@ -586,7 +586,7 @@ async function saveQueryLocalCacheQuery(query, rows, options) {
|
|
|
586
586
|
sql: sql2.toSQL().sql.toLowerCase(),
|
|
587
587
|
data: rows
|
|
588
588
|
};
|
|
589
|
-
if (options.
|
|
589
|
+
if (options.logCache) {
|
|
590
590
|
const q = sql2.toSQL();
|
|
591
591
|
console.debug(
|
|
592
592
|
`[forge-sql-orm][local-cache][SAVE] Stored result in cache. sql="${q.sql}", params=${JSON.stringify(q.params)}`
|
|
@@ -603,7 +603,7 @@ async function getQueryLocalCacheQuery(query, options) {
|
|
|
603
603
|
const sql2 = query;
|
|
604
604
|
const key = hashKey(sql2.toSQL());
|
|
605
605
|
if (context.cache[key] && context.cache[key].sql === sql2.toSQL().sql.toLowerCase()) {
|
|
606
|
-
if (options.
|
|
606
|
+
if (options.logCache) {
|
|
607
607
|
const q = sql2.toSQL();
|
|
608
608
|
console.debug(
|
|
609
609
|
`[forge-sql-orm][local-cache][HIT] Returned cached result. sql="${q.sql}", params=${JSON.stringify(q.params)}`
|
|
@@ -1034,6 +1034,18 @@ class ForgeSQLSelectOperations {
|
|
|
1034
1034
|
return updateQueryResponseResults.rows;
|
|
1035
1035
|
}
|
|
1036
1036
|
}
|
|
1037
|
+
const metadataQueryContext = new node_async_hooks.AsyncLocalStorage();
|
|
1038
|
+
async function saveMetaDataInContextContext(metadata) {
|
|
1039
|
+
const context = metadataQueryContext.getStore();
|
|
1040
|
+
if (context && metadata) {
|
|
1041
|
+
context.totalResponseSize += metadata.responseSize;
|
|
1042
|
+
context.totalDbExecutionTime += metadata.dbExecutionTime;
|
|
1043
|
+
context.lastMetadata = metadata;
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
async function getLastestMetadata() {
|
|
1047
|
+
return metadataQueryContext.getStore();
|
|
1048
|
+
}
|
|
1037
1049
|
const forgeDriver = async (query, params, method) => {
|
|
1038
1050
|
if (method == "execute") {
|
|
1039
1051
|
const sqlStatement = sql$1.sql.prepare(query);
|
|
@@ -1049,6 +1061,7 @@ const forgeDriver = async (query, params, method) => {
|
|
|
1049
1061
|
await sqlStatement.bindParams(...params);
|
|
1050
1062
|
}
|
|
1051
1063
|
const result = await sqlStatement.execute();
|
|
1064
|
+
await saveMetaDataInContextContext(result.metadata);
|
|
1052
1065
|
let rows;
|
|
1053
1066
|
rows = result.rows.map((r) => Object.values(r));
|
|
1054
1067
|
return { rows };
|
|
@@ -1798,6 +1811,7 @@ class ForgeSQLORMImpl {
|
|
|
1798
1811
|
try {
|
|
1799
1812
|
const newOptions = options ?? {
|
|
1800
1813
|
logRawSqlQuery: false,
|
|
1814
|
+
logCache: false,
|
|
1801
1815
|
disableOptimisticLocking: false,
|
|
1802
1816
|
cacheWrapTable: true,
|
|
1803
1817
|
cacheTTL: 120,
|
|
@@ -1823,6 +1837,42 @@ class ForgeSQLORMImpl {
|
|
|
1823
1837
|
throw error;
|
|
1824
1838
|
}
|
|
1825
1839
|
}
|
|
1840
|
+
/**
|
|
1841
|
+
* Executes a query and provides access to execution metadata.
|
|
1842
|
+
* This method allows you to capture detailed information about query execution
|
|
1843
|
+
* including database execution time, response size, and Forge SQL metadata.
|
|
1844
|
+
*
|
|
1845
|
+
* @template T - The return type of the query
|
|
1846
|
+
* @param query - A function that returns a Promise with the query result
|
|
1847
|
+
* @param onMetadata - Callback function that receives execution metadata
|
|
1848
|
+
* @returns Promise with the query result
|
|
1849
|
+
* @example
|
|
1850
|
+
* ```typescript
|
|
1851
|
+
* const result = await forgeSQL.executeWithMetadata(
|
|
1852
|
+
* async () => await forgeSQL.select().from(users).where(eq(users.id, 1)),
|
|
1853
|
+
* (dbTime, responseSize, metadata) => {
|
|
1854
|
+
* console.log(`DB execution time: ${dbTime}ms`);
|
|
1855
|
+
* console.log(`Response size: ${responseSize} bytes`);
|
|
1856
|
+
* console.log('Forge metadata:', metadata);
|
|
1857
|
+
* }
|
|
1858
|
+
* );
|
|
1859
|
+
* ```
|
|
1860
|
+
*/
|
|
1861
|
+
async executeWithMetadata(query, onMetadata) {
|
|
1862
|
+
return metadataQueryContext.run({
|
|
1863
|
+
totalDbExecutionTime: 0,
|
|
1864
|
+
totalResponseSize: 0
|
|
1865
|
+
}, async () => {
|
|
1866
|
+
try {
|
|
1867
|
+
return await query();
|
|
1868
|
+
} finally {
|
|
1869
|
+
const metadata = await getLastestMetadata();
|
|
1870
|
+
if (metadata && metadata.lastMetadata) {
|
|
1871
|
+
await onMetadata(metadata.totalDbExecutionTime, metadata.totalResponseSize, metadata.lastMetadata);
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1874
|
+
});
|
|
1875
|
+
}
|
|
1826
1876
|
/**
|
|
1827
1877
|
* Executes operations within a cache context that collects cache eviction events.
|
|
1828
1878
|
* All clearCache calls within the context are collected and executed in batch at the end.
|
|
@@ -2270,6 +2320,30 @@ class ForgeSQLORM {
|
|
|
2270
2320
|
constructor(options) {
|
|
2271
2321
|
this.ormInstance = ForgeSQLORMImpl.getInstance(options);
|
|
2272
2322
|
}
|
|
2323
|
+
/**
|
|
2324
|
+
* Executes a query and provides access to execution metadata.
|
|
2325
|
+
* This method allows you to capture detailed information about query execution
|
|
2326
|
+
* including database execution time, response size, and Forge SQL metadata.
|
|
2327
|
+
*
|
|
2328
|
+
* @template T - The return type of the query
|
|
2329
|
+
* @param query - A function that returns a Promise with the query result
|
|
2330
|
+
* @param onMetadata - Callback function that receives execution metadata
|
|
2331
|
+
* @returns Promise with the query result
|
|
2332
|
+
* @example
|
|
2333
|
+
* ```typescript
|
|
2334
|
+
* const result = await forgeSQL.executeWithMetadata(
|
|
2335
|
+
* async () => await forgeSQL.select().from(users).where(eq(users.id, 1)),
|
|
2336
|
+
* (dbTime, responseSize, metadata) => {
|
|
2337
|
+
* console.log(`DB execution time: ${dbTime}ms`);
|
|
2338
|
+
* console.log(`Response size: ${responseSize} bytes`);
|
|
2339
|
+
* console.log('Forge metadata:', metadata);
|
|
2340
|
+
* }
|
|
2341
|
+
* );
|
|
2342
|
+
* ```
|
|
2343
|
+
*/
|
|
2344
|
+
async executeWithMetadata(query, onMetadata) {
|
|
2345
|
+
return this.ormInstance.executeWithMetadata(query, onMetadata);
|
|
2346
|
+
}
|
|
2273
2347
|
selectCacheable(fields, cacheTTL) {
|
|
2274
2348
|
return this.ormInstance.selectCacheable(fields, cacheTTL);
|
|
2275
2349
|
}
|
|
@@ -2642,6 +2716,435 @@ const migrations = mysqlCore.mysqlTable("__migrations", {
|
|
|
2642
2716
|
name: mysqlCore.varchar("name", { length: 255 }).notNull(),
|
|
2643
2717
|
migratedAt: mysqlCore.timestamp("migratedAt").defaultNow().notNull()
|
|
2644
2718
|
});
|
|
2719
|
+
const informationSchema = mysqlCore.mysqlSchema("information_schema");
|
|
2720
|
+
const slowQuery = informationSchema.table("SLOW_QUERY", {
|
|
2721
|
+
time: mysqlCore.timestamp("Time", { fsp: 6, mode: "string" }).notNull(),
|
|
2722
|
+
// Timestamp when the slow query was recorded
|
|
2723
|
+
txnStartTs: mysqlCore.bigint("Txn_start_ts", { mode: "bigint", unsigned: true }),
|
|
2724
|
+
// Transaction start timestamp (TSO)
|
|
2725
|
+
user: mysqlCore.varchar("User", { length: 64 }),
|
|
2726
|
+
// User executing the query
|
|
2727
|
+
host: mysqlCore.varchar("Host", { length: 64 }),
|
|
2728
|
+
// Host from which the query originated
|
|
2729
|
+
connId: mysqlCore.bigint("Conn_ID", { mode: "bigint", unsigned: true }),
|
|
2730
|
+
// Connection ID
|
|
2731
|
+
sessionAlias: mysqlCore.varchar("Session_alias", { length: 64 }),
|
|
2732
|
+
// Session alias
|
|
2733
|
+
execRetryCount: mysqlCore.bigint("Exec_retry_count", { mode: "bigint", unsigned: true }),
|
|
2734
|
+
// Number of retries during execution
|
|
2735
|
+
execRetryTime: mysqlCore.double("Exec_retry_time"),
|
|
2736
|
+
// Time spent in retries
|
|
2737
|
+
queryTime: mysqlCore.double("Query_time"),
|
|
2738
|
+
// Total execution time
|
|
2739
|
+
parseTime: mysqlCore.double("Parse_time"),
|
|
2740
|
+
// Time spent parsing SQL
|
|
2741
|
+
compileTime: mysqlCore.double("Compile_time"),
|
|
2742
|
+
// Time spent compiling query plan
|
|
2743
|
+
rewriteTime: mysqlCore.double("Rewrite_time"),
|
|
2744
|
+
// Time spent rewriting query
|
|
2745
|
+
preprocSubqueries: mysqlCore.bigint("Preproc_subqueries", { mode: "bigint", unsigned: true }),
|
|
2746
|
+
// Number of subqueries preprocessed
|
|
2747
|
+
preprocSubqueriesTime: mysqlCore.double("Preproc_subqueries_time"),
|
|
2748
|
+
// Time spent preprocessing subqueries
|
|
2749
|
+
optimizeTime: mysqlCore.double("Optimize_time"),
|
|
2750
|
+
// Time spent in optimizer
|
|
2751
|
+
waitTs: mysqlCore.double("Wait_TS"),
|
|
2752
|
+
// Wait time for getting TSO
|
|
2753
|
+
prewriteTime: mysqlCore.double("Prewrite_time"),
|
|
2754
|
+
// Time spent in prewrite phase
|
|
2755
|
+
waitPrewriteBinlogTime: mysqlCore.double("Wait_prewrite_binlog_time"),
|
|
2756
|
+
// Time waiting for binlog prewrite
|
|
2757
|
+
commitTime: mysqlCore.double("Commit_time"),
|
|
2758
|
+
// Commit duration
|
|
2759
|
+
getCommitTsTime: mysqlCore.double("Get_commit_ts_time"),
|
|
2760
|
+
// Time waiting for commit TSO
|
|
2761
|
+
commitBackoffTime: mysqlCore.double("Commit_backoff_time"),
|
|
2762
|
+
// Backoff time during commit
|
|
2763
|
+
backoffTypes: mysqlCore.varchar("Backoff_types", { length: 64 }),
|
|
2764
|
+
// Types of backoff occurred
|
|
2765
|
+
resolveLockTime: mysqlCore.double("Resolve_lock_time"),
|
|
2766
|
+
// Time resolving locks
|
|
2767
|
+
localLatchWaitTime: mysqlCore.double("Local_latch_wait_time"),
|
|
2768
|
+
// Time waiting on local latch
|
|
2769
|
+
writeKeys: mysqlCore.bigint("Write_keys", { mode: "bigint" }),
|
|
2770
|
+
// Number of keys written
|
|
2771
|
+
writeSize: mysqlCore.bigint("Write_size", { mode: "bigint" }),
|
|
2772
|
+
// Amount of data written
|
|
2773
|
+
prewriteRegion: mysqlCore.bigint("Prewrite_region", { mode: "bigint" }),
|
|
2774
|
+
// Regions involved in prewrite
|
|
2775
|
+
txnRetry: mysqlCore.bigint("Txn_retry", { mode: "bigint" }),
|
|
2776
|
+
// Transaction retry count
|
|
2777
|
+
copTime: mysqlCore.double("Cop_time"),
|
|
2778
|
+
// Time spent in coprocessor
|
|
2779
|
+
processTime: mysqlCore.double("Process_time"),
|
|
2780
|
+
// Processing time
|
|
2781
|
+
waitTime: mysqlCore.double("Wait_time"),
|
|
2782
|
+
// Wait time in TiKV
|
|
2783
|
+
backoffTime: mysqlCore.double("Backoff_time"),
|
|
2784
|
+
// Backoff wait time
|
|
2785
|
+
lockKeysTime: mysqlCore.double("LockKeys_time"),
|
|
2786
|
+
// Time spent waiting for locks
|
|
2787
|
+
requestCount: mysqlCore.bigint("Request_count", { mode: "bigint", unsigned: true }),
|
|
2788
|
+
// Total number of requests
|
|
2789
|
+
totalKeys: mysqlCore.bigint("Total_keys", { mode: "bigint", unsigned: true }),
|
|
2790
|
+
// Total keys scanned
|
|
2791
|
+
processKeys: mysqlCore.bigint("Process_keys", { mode: "bigint", unsigned: true }),
|
|
2792
|
+
// Keys processed
|
|
2793
|
+
rocksdbDeleteSkippedCount: mysqlCore.bigint("Rocksdb_delete_skipped_count", {
|
|
2794
|
+
mode: "bigint",
|
|
2795
|
+
unsigned: true
|
|
2796
|
+
}),
|
|
2797
|
+
// RocksDB delete skips
|
|
2798
|
+
rocksdbKeySkippedCount: mysqlCore.bigint("Rocksdb_key_skipped_count", { mode: "bigint", unsigned: true }),
|
|
2799
|
+
// RocksDB key skips
|
|
2800
|
+
rocksdbBlockCacheHitCount: mysqlCore.bigint("Rocksdb_block_cache_hit_count", {
|
|
2801
|
+
mode: "bigint",
|
|
2802
|
+
unsigned: true
|
|
2803
|
+
}),
|
|
2804
|
+
// RocksDB block cache hits
|
|
2805
|
+
rocksdbBlockReadCount: mysqlCore.bigint("Rocksdb_block_read_count", { mode: "bigint", unsigned: true }),
|
|
2806
|
+
// RocksDB block reads
|
|
2807
|
+
rocksdbBlockReadByte: mysqlCore.bigint("Rocksdb_block_read_byte", { mode: "bigint", unsigned: true }),
|
|
2808
|
+
// RocksDB block read bytes
|
|
2809
|
+
db: mysqlCore.varchar("DB", { length: 64 }),
|
|
2810
|
+
// Database name
|
|
2811
|
+
indexNames: mysqlCore.varchar("Index_names", { length: 100 }),
|
|
2812
|
+
// Indexes used
|
|
2813
|
+
isInternal: mysqlCore.boolean("Is_internal"),
|
|
2814
|
+
// Whether the query is internal
|
|
2815
|
+
digest: mysqlCore.varchar("Digest", { length: 64 }),
|
|
2816
|
+
// SQL digest hash
|
|
2817
|
+
stats: mysqlCore.varchar("Stats", { length: 512 }),
|
|
2818
|
+
// Stats used during planning
|
|
2819
|
+
copProcAvg: mysqlCore.double("Cop_proc_avg"),
|
|
2820
|
+
// Coprocessor average processing time
|
|
2821
|
+
copProcP90: mysqlCore.double("Cop_proc_p90"),
|
|
2822
|
+
// Coprocessor 90th percentile processing time
|
|
2823
|
+
copProcMax: mysqlCore.double("Cop_proc_max"),
|
|
2824
|
+
// Coprocessor max processing time
|
|
2825
|
+
copProcAddr: mysqlCore.varchar("Cop_proc_addr", { length: 64 }),
|
|
2826
|
+
// Coprocessor address for processing
|
|
2827
|
+
copWaitAvg: mysqlCore.double("Cop_wait_avg"),
|
|
2828
|
+
// Coprocessor average wait time
|
|
2829
|
+
copWaitP90: mysqlCore.double("Cop_wait_p90"),
|
|
2830
|
+
// Coprocessor 90th percentile wait time
|
|
2831
|
+
copWaitMax: mysqlCore.double("Cop_wait_max"),
|
|
2832
|
+
// Coprocessor max wait time
|
|
2833
|
+
copWaitAddr: mysqlCore.varchar("Cop_wait_addr", { length: 64 }),
|
|
2834
|
+
// Coprocessor address for wait
|
|
2835
|
+
memMax: mysqlCore.bigint("Mem_max", { mode: "bigint" }),
|
|
2836
|
+
// Max memory usage
|
|
2837
|
+
diskMax: mysqlCore.bigint("Disk_max", { mode: "bigint" }),
|
|
2838
|
+
// Max disk usage
|
|
2839
|
+
kvTotal: mysqlCore.double("KV_total"),
|
|
2840
|
+
// Total KV request time
|
|
2841
|
+
pdTotal: mysqlCore.double("PD_total"),
|
|
2842
|
+
// Total PD request time
|
|
2843
|
+
backoffTotal: mysqlCore.double("Backoff_total"),
|
|
2844
|
+
// Total backoff time
|
|
2845
|
+
writeSqlResponseTotal: mysqlCore.double("Write_sql_response_total"),
|
|
2846
|
+
// SQL response write time
|
|
2847
|
+
resultRows: mysqlCore.bigint("Result_rows", { mode: "bigint" }),
|
|
2848
|
+
// Rows returned
|
|
2849
|
+
warnings: mysqlCore.longtext("Warnings"),
|
|
2850
|
+
// Warnings during execution
|
|
2851
|
+
backoffDetail: mysqlCore.varchar("Backoff_Detail", { length: 4096 }),
|
|
2852
|
+
// Detailed backoff info
|
|
2853
|
+
prepared: mysqlCore.boolean("Prepared"),
|
|
2854
|
+
// Whether query was prepared
|
|
2855
|
+
succ: mysqlCore.boolean("Succ"),
|
|
2856
|
+
// Success flag
|
|
2857
|
+
isExplicitTxn: mysqlCore.boolean("IsExplicitTxn"),
|
|
2858
|
+
// Whether explicit transaction
|
|
2859
|
+
isWriteCacheTable: mysqlCore.boolean("IsWriteCacheTable"),
|
|
2860
|
+
// Whether wrote to cache table
|
|
2861
|
+
planFromCache: mysqlCore.boolean("Plan_from_cache"),
|
|
2862
|
+
// Plan was from cache
|
|
2863
|
+
planFromBinding: mysqlCore.boolean("Plan_from_binding"),
|
|
2864
|
+
// Plan was from binding
|
|
2865
|
+
hasMoreResults: mysqlCore.boolean("Has_more_results"),
|
|
2866
|
+
// Query returned multiple results
|
|
2867
|
+
resourceGroup: mysqlCore.varchar("Resource_group", { length: 64 }),
|
|
2868
|
+
// Resource group name
|
|
2869
|
+
requestUnitRead: mysqlCore.double("Request_unit_read"),
|
|
2870
|
+
// RU consumed for read
|
|
2871
|
+
requestUnitWrite: mysqlCore.double("Request_unit_write"),
|
|
2872
|
+
// RU consumed for write
|
|
2873
|
+
timeQueuedByRc: mysqlCore.double("Time_queued_by_rc"),
|
|
2874
|
+
// Time queued by resource control
|
|
2875
|
+
tidbCpuTime: mysqlCore.double("Tidb_cpu_time"),
|
|
2876
|
+
// TiDB CPU time
|
|
2877
|
+
tikvCpuTime: mysqlCore.double("Tikv_cpu_time"),
|
|
2878
|
+
// TiKV CPU time
|
|
2879
|
+
plan: mysqlCore.longtext("Plan"),
|
|
2880
|
+
// Query execution plan
|
|
2881
|
+
planDigest: mysqlCore.varchar("Plan_digest", { length: 128 }),
|
|
2882
|
+
// Plan digest hash
|
|
2883
|
+
binaryPlan: mysqlCore.longtext("Binary_plan"),
|
|
2884
|
+
// Binary execution plan
|
|
2885
|
+
prevStmt: mysqlCore.longtext("Prev_stmt"),
|
|
2886
|
+
// Previous statement in session
|
|
2887
|
+
query: mysqlCore.longtext("Query")
|
|
2888
|
+
// Original SQL query
|
|
2889
|
+
});
|
|
2890
|
+
const createClusterStatementsSummarySchema = () => ({
|
|
2891
|
+
instance: mysqlCore.varchar("INSTANCE", { length: 64 }),
|
|
2892
|
+
// TiDB/TiKV instance address
|
|
2893
|
+
summaryBeginTime: mysqlCore.timestamp("SUMMARY_BEGIN_TIME", { mode: "string" }).notNull(),
|
|
2894
|
+
// Begin time of this summary window
|
|
2895
|
+
summaryEndTime: mysqlCore.timestamp("SUMMARY_END_TIME", { mode: "string" }).notNull(),
|
|
2896
|
+
// End time of this summary window
|
|
2897
|
+
stmtType: mysqlCore.varchar("STMT_TYPE", { length: 64 }).notNull(),
|
|
2898
|
+
// Statement type (e.g., Select/Insert/Update)
|
|
2899
|
+
schemaName: mysqlCore.varchar("SCHEMA_NAME", { length: 64 }),
|
|
2900
|
+
// Current schema name
|
|
2901
|
+
digest: mysqlCore.varchar("DIGEST", { length: 64 }),
|
|
2902
|
+
// SQL digest (normalized hash)
|
|
2903
|
+
digestText: mysqlCore.text("DIGEST_TEXT").notNull(),
|
|
2904
|
+
// Normalized SQL text
|
|
2905
|
+
tableNames: mysqlCore.text("TABLE_NAMES"),
|
|
2906
|
+
// Involved table names
|
|
2907
|
+
indexNames: mysqlCore.text("INDEX_NAMES"),
|
|
2908
|
+
// Used index names
|
|
2909
|
+
sampleUser: mysqlCore.varchar("SAMPLE_USER", { length: 64 }),
|
|
2910
|
+
// Sampled user who executed the statements
|
|
2911
|
+
execCount: mysqlCore.bigint("EXEC_COUNT", { mode: "bigint", unsigned: true }).notNull(),
|
|
2912
|
+
// Total executions
|
|
2913
|
+
sumErrors: mysqlCore.int("SUM_ERRORS", { unsigned: true }).notNull(),
|
|
2914
|
+
// Sum of errors
|
|
2915
|
+
sumWarnings: mysqlCore.int("SUM_WARNINGS", { unsigned: true }).notNull(),
|
|
2916
|
+
// Sum of warnings
|
|
2917
|
+
sumLatency: mysqlCore.bigint("SUM_LATENCY", { mode: "bigint", unsigned: true }).notNull(),
|
|
2918
|
+
// Sum of latency (ns)
|
|
2919
|
+
maxLatency: mysqlCore.bigint("MAX_LATENCY", { mode: "bigint", unsigned: true }).notNull(),
|
|
2920
|
+
// Max latency (ns)
|
|
2921
|
+
minLatency: mysqlCore.bigint("MIN_LATENCY", { mode: "bigint", unsigned: true }).notNull(),
|
|
2922
|
+
// Min latency (ns)
|
|
2923
|
+
avgLatency: mysqlCore.bigint("AVG_LATENCY", { mode: "bigint", unsigned: true }).notNull(),
|
|
2924
|
+
// Avg latency (ns)
|
|
2925
|
+
avgParseLatency: mysqlCore.bigint("AVG_PARSE_LATENCY", { mode: "bigint", unsigned: true }).notNull(),
|
|
2926
|
+
// Avg parse time (ns)
|
|
2927
|
+
maxParseLatency: mysqlCore.bigint("MAX_PARSE_LATENCY", { mode: "bigint", unsigned: true }).notNull(),
|
|
2928
|
+
// Max parse time (ns)
|
|
2929
|
+
avgCompileLatency: mysqlCore.bigint("AVG_COMPILE_LATENCY", { mode: "bigint", unsigned: true }).notNull(),
|
|
2930
|
+
// Avg compile time (ns)
|
|
2931
|
+
maxCompileLatency: mysqlCore.bigint("MAX_COMPILE_LATENCY", { mode: "bigint", unsigned: true }).notNull(),
|
|
2932
|
+
// Max compile time (ns)
|
|
2933
|
+
sumCopTaskNum: mysqlCore.bigint("SUM_COP_TASK_NUM", { mode: "bigint", unsigned: true }).notNull(),
|
|
2934
|
+
// Total number of cop tasks
|
|
2935
|
+
maxCopProcessTime: mysqlCore.bigint("MAX_COP_PROCESS_TIME", { mode: "bigint", unsigned: true }).notNull(),
|
|
2936
|
+
// Max TiKV coprocessor processing time (ns)
|
|
2937
|
+
maxCopProcessAddress: mysqlCore.varchar("MAX_COP_PROCESS_ADDRESS", { length: 256 }),
|
|
2938
|
+
// Address of cop task with max processing time
|
|
2939
|
+
maxCopWaitTime: mysqlCore.bigint("MAX_COP_WAIT_TIME", { mode: "bigint", unsigned: true }).notNull(),
|
|
2940
|
+
// Max TiKV coprocessor wait time (ns)
|
|
2941
|
+
maxCopWaitAddress: mysqlCore.varchar("MAX_COP_WAIT_ADDRESS", { length: 256 }),
|
|
2942
|
+
// Address of cop task with max wait time
|
|
2943
|
+
avgProcessTime: mysqlCore.bigint("AVG_PROCESS_TIME", { mode: "bigint", unsigned: true }).notNull(),
|
|
2944
|
+
// Avg TiKV processing time (ns)
|
|
2945
|
+
maxProcessTime: mysqlCore.bigint("MAX_PROCESS_TIME", { mode: "bigint", unsigned: true }).notNull(),
|
|
2946
|
+
// Max TiKV processing time (ns)
|
|
2947
|
+
avgWaitTime: mysqlCore.bigint("AVG_WAIT_TIME", { mode: "bigint", unsigned: true }).notNull(),
|
|
2948
|
+
// Avg TiKV wait time (ns)
|
|
2949
|
+
maxWaitTime: mysqlCore.bigint("MAX_WAIT_TIME", { mode: "bigint", unsigned: true }).notNull(),
|
|
2950
|
+
// Max TiKV wait time (ns)
|
|
2951
|
+
avgBackoffTime: mysqlCore.bigint("AVG_BACKOFF_TIME", { mode: "bigint", unsigned: true }).notNull(),
|
|
2952
|
+
// Avg backoff time before retry (ns)
|
|
2953
|
+
maxBackoffTime: mysqlCore.bigint("MAX_BACKOFF_TIME", { mode: "bigint", unsigned: true }).notNull(),
|
|
2954
|
+
// Max backoff time before retry (ns)
|
|
2955
|
+
avgTotalKeys: mysqlCore.bigint("AVG_TOTAL_KEYS", { mode: "bigint", unsigned: true }).notNull(),
|
|
2956
|
+
// Avg scanned keys
|
|
2957
|
+
maxTotalKeys: mysqlCore.bigint("MAX_TOTAL_KEYS", { mode: "bigint", unsigned: true }).notNull(),
|
|
2958
|
+
// Max scanned keys
|
|
2959
|
+
avgProcessedKeys: mysqlCore.bigint("AVG_PROCESSED_KEYS", { mode: "bigint", unsigned: true }).notNull(),
|
|
2960
|
+
// Avg processed keys
|
|
2961
|
+
maxProcessedKeys: mysqlCore.bigint("MAX_PROCESSED_KEYS", { mode: "bigint", unsigned: true }).notNull(),
|
|
2962
|
+
// Max processed keys
|
|
2963
|
+
avgRocksdbDeleteSkippedCount: mysqlCore.double("AVG_ROCKSDB_DELETE_SKIPPED_COUNT").notNull(),
|
|
2964
|
+
// Avg RocksDB deletes skipped
|
|
2965
|
+
maxRocksdbDeleteSkippedCount: mysqlCore.int("MAX_ROCKSDB_DELETE_SKIPPED_COUNT", {
|
|
2966
|
+
unsigned: true
|
|
2967
|
+
}).notNull(),
|
|
2968
|
+
// Max RocksDB deletes skipped
|
|
2969
|
+
avgRocksdbKeySkippedCount: mysqlCore.double("AVG_ROCKSDB_KEY_SKIPPED_COUNT").notNull(),
|
|
2970
|
+
// Avg RocksDB keys skipped
|
|
2971
|
+
maxRocksdbKeySkippedCount: mysqlCore.int("MAX_ROCKSDB_KEY_SKIPPED_COUNT", { unsigned: true }).notNull(),
|
|
2972
|
+
// Max RocksDB keys skipped
|
|
2973
|
+
avgRocksdbBlockCacheHitCount: mysqlCore.double("AVG_ROCKSDB_BLOCK_CACHE_HIT_COUNT").notNull(),
|
|
2974
|
+
// Avg RocksDB block cache hits
|
|
2975
|
+
maxRocksdbBlockCacheHitCount: mysqlCore.int("MAX_ROCKSDB_BLOCK_CACHE_HIT_COUNT", {
|
|
2976
|
+
unsigned: true
|
|
2977
|
+
}).notNull(),
|
|
2978
|
+
// Max RocksDB block cache hits
|
|
2979
|
+
avgRocksdbBlockReadCount: mysqlCore.double("AVG_ROCKSDB_BLOCK_READ_COUNT").notNull(),
|
|
2980
|
+
// Avg RocksDB block reads
|
|
2981
|
+
maxRocksdbBlockReadCount: mysqlCore.int("MAX_ROCKSDB_BLOCK_READ_COUNT", { unsigned: true }).notNull(),
|
|
2982
|
+
// Max RocksDB block reads
|
|
2983
|
+
avgRocksdbBlockReadByte: mysqlCore.double("AVG_ROCKSDB_BLOCK_READ_BYTE").notNull(),
|
|
2984
|
+
// Avg RocksDB block read bytes
|
|
2985
|
+
maxRocksdbBlockReadByte: mysqlCore.int("MAX_ROCKSDB_BLOCK_READ_BYTE", { unsigned: true }).notNull(),
|
|
2986
|
+
// Max RocksDB block read bytes
|
|
2987
|
+
avgPrewriteTime: mysqlCore.bigint("AVG_PREWRITE_TIME", { mode: "bigint", unsigned: true }).notNull(),
|
|
2988
|
+
// Avg prewrite phase time (ns)
|
|
2989
|
+
maxPrewriteTime: mysqlCore.bigint("MAX_PREWRITE_TIME", { mode: "bigint", unsigned: true }).notNull(),
|
|
2990
|
+
// Max prewrite phase time (ns)
|
|
2991
|
+
avgCommitTime: mysqlCore.bigint("AVG_COMMIT_TIME", { mode: "bigint", unsigned: true }).notNull(),
|
|
2992
|
+
// Avg commit phase time (ns)
|
|
2993
|
+
maxCommitTime: mysqlCore.bigint("MAX_COMMIT_TIME", { mode: "bigint", unsigned: true }).notNull(),
|
|
2994
|
+
// Max commit phase time (ns)
|
|
2995
|
+
avgGetCommitTsTime: mysqlCore.bigint("AVG_GET_COMMIT_TS_TIME", {
|
|
2996
|
+
mode: "bigint",
|
|
2997
|
+
unsigned: true
|
|
2998
|
+
}).notNull(),
|
|
2999
|
+
// Avg get commit_ts time (ns)
|
|
3000
|
+
maxGetCommitTsTime: mysqlCore.bigint("MAX_GET_COMMIT_TS_TIME", {
|
|
3001
|
+
mode: "bigint",
|
|
3002
|
+
unsigned: true
|
|
3003
|
+
}).notNull(),
|
|
3004
|
+
// Max get commit_ts time (ns)
|
|
3005
|
+
avgCommitBackoffTime: mysqlCore.bigint("AVG_COMMIT_BACKOFF_TIME", {
|
|
3006
|
+
mode: "bigint",
|
|
3007
|
+
unsigned: true
|
|
3008
|
+
}).notNull(),
|
|
3009
|
+
// Avg backoff during commit (ns)
|
|
3010
|
+
maxCommitBackoffTime: mysqlCore.bigint("MAX_COMMIT_BACKOFF_TIME", {
|
|
3011
|
+
mode: "bigint",
|
|
3012
|
+
unsigned: true
|
|
3013
|
+
}).notNull(),
|
|
3014
|
+
// Max backoff during commit (ns)
|
|
3015
|
+
avgResolveLockTime: mysqlCore.bigint("AVG_RESOLVE_LOCK_TIME", {
|
|
3016
|
+
mode: "bigint",
|
|
3017
|
+
unsigned: true
|
|
3018
|
+
}).notNull(),
|
|
3019
|
+
// Avg resolve lock time (ns)
|
|
3020
|
+
maxResolveLockTime: mysqlCore.bigint("MAX_RESOLVE_LOCK_TIME", {
|
|
3021
|
+
mode: "bigint",
|
|
3022
|
+
unsigned: true
|
|
3023
|
+
}).notNull(),
|
|
3024
|
+
// Max resolve lock time (ns)
|
|
3025
|
+
avgLocalLatchWaitTime: mysqlCore.bigint("AVG_LOCAL_LATCH_WAIT_TIME", {
|
|
3026
|
+
mode: "bigint",
|
|
3027
|
+
unsigned: true
|
|
3028
|
+
}).notNull(),
|
|
3029
|
+
// Avg local latch wait (ns)
|
|
3030
|
+
maxLocalLatchWaitTime: mysqlCore.bigint("MAX_LOCAL_LATCH_WAIT_TIME", {
|
|
3031
|
+
mode: "bigint",
|
|
3032
|
+
unsigned: true
|
|
3033
|
+
}).notNull(),
|
|
3034
|
+
// Max local latch wait (ns)
|
|
3035
|
+
avgWriteKeys: mysqlCore.double("AVG_WRITE_KEYS").notNull(),
|
|
3036
|
+
// Avg number of written keys
|
|
3037
|
+
maxWriteKeys: mysqlCore.bigint("MAX_WRITE_KEYS", { mode: "bigint", unsigned: true }).notNull(),
|
|
3038
|
+
// Max written keys
|
|
3039
|
+
avgWriteSize: mysqlCore.double("AVG_WRITE_SIZE").notNull(),
|
|
3040
|
+
// Avg written bytes
|
|
3041
|
+
maxWriteSize: mysqlCore.bigint("MAX_WRITE_SIZE", { mode: "bigint", unsigned: true }).notNull(),
|
|
3042
|
+
// Max written bytes
|
|
3043
|
+
avgPrewriteRegions: mysqlCore.double("AVG_PREWRITE_REGIONS").notNull(),
|
|
3044
|
+
// Avg regions in prewrite
|
|
3045
|
+
maxPrewriteRegions: mysqlCore.int("MAX_PREWRITE_REGIONS", { unsigned: true }).notNull(),
|
|
3046
|
+
// Max regions in prewrite
|
|
3047
|
+
avgTxnRetry: mysqlCore.double("AVG_TXN_RETRY").notNull(),
|
|
3048
|
+
// Avg transaction retry count
|
|
3049
|
+
maxTxnRetry: mysqlCore.int("MAX_TXN_RETRY", { unsigned: true }).notNull(),
|
|
3050
|
+
// Max transaction retry count
|
|
3051
|
+
sumExecRetry: mysqlCore.bigint("SUM_EXEC_RETRY", { mode: "bigint", unsigned: true }).notNull(),
|
|
3052
|
+
// Sum of execution retries (pessimistic)
|
|
3053
|
+
sumExecRetryTime: mysqlCore.bigint("SUM_EXEC_RETRY_TIME", { mode: "bigint", unsigned: true }).notNull(),
|
|
3054
|
+
// Sum time of execution retries (ns)
|
|
3055
|
+
sumBackoffTimes: mysqlCore.bigint("SUM_BACKOFF_TIMES", { mode: "bigint", unsigned: true }).notNull(),
|
|
3056
|
+
// Sum of backoff retries
|
|
3057
|
+
backoffTypes: mysqlCore.varchar("BACKOFF_TYPES", { length: 1024 }),
|
|
3058
|
+
// Backoff types with counts
|
|
3059
|
+
avgMem: mysqlCore.bigint("AVG_MEM", { mode: "bigint", unsigned: true }).notNull(),
|
|
3060
|
+
// Avg memory used (bytes)
|
|
3061
|
+
maxMem: mysqlCore.bigint("MAX_MEM", { mode: "bigint", unsigned: true }).notNull(),
|
|
3062
|
+
// Max memory used (bytes)
|
|
3063
|
+
avgDisk: mysqlCore.bigint("AVG_DISK", { mode: "bigint", unsigned: true }).notNull(),
|
|
3064
|
+
// Avg disk used (bytes)
|
|
3065
|
+
maxDisk: mysqlCore.bigint("MAX_DISK", { mode: "bigint", unsigned: true }).notNull(),
|
|
3066
|
+
// Max disk used (bytes)
|
|
3067
|
+
avgKvTime: mysqlCore.bigint("AVG_KV_TIME", { mode: "bigint", unsigned: true }).notNull(),
|
|
3068
|
+
// Avg time spent in TiKV (ns)
|
|
3069
|
+
avgPdTime: mysqlCore.bigint("AVG_PD_TIME", { mode: "bigint", unsigned: true }).notNull(),
|
|
3070
|
+
// Avg time spent in PD (ns)
|
|
3071
|
+
avgBackoffTotalTime: mysqlCore.bigint("AVG_BACKOFF_TOTAL_TIME", {
|
|
3072
|
+
mode: "bigint",
|
|
3073
|
+
unsigned: true
|
|
3074
|
+
}).notNull(),
|
|
3075
|
+
// Avg total backoff time (ns)
|
|
3076
|
+
avgWriteSqlRespTime: mysqlCore.bigint("AVG_WRITE_SQL_RESP_TIME", {
|
|
3077
|
+
mode: "bigint",
|
|
3078
|
+
unsigned: true
|
|
3079
|
+
}).notNull(),
|
|
3080
|
+
// Avg write SQL response time (ns)
|
|
3081
|
+
avgTidbCpuTime: mysqlCore.bigint("AVG_TIDB_CPU_TIME", { mode: "bigint", unsigned: true }).notNull(),
|
|
3082
|
+
// Avg TiDB CPU time (ns)
|
|
3083
|
+
avgTikvCpuTime: mysqlCore.bigint("AVG_TIKV_CPU_TIME", { mode: "bigint", unsigned: true }).notNull(),
|
|
3084
|
+
// Avg TiKV CPU time (ns)
|
|
3085
|
+
maxResultRows: mysqlCore.bigint("MAX_RESULT_ROWS", { mode: "bigint" }).notNull(),
|
|
3086
|
+
// Max number of result rows
|
|
3087
|
+
minResultRows: mysqlCore.bigint("MIN_RESULT_ROWS", { mode: "bigint" }).notNull(),
|
|
3088
|
+
// Min number of result rows
|
|
3089
|
+
avgResultRows: mysqlCore.bigint("AVG_RESULT_ROWS", { mode: "bigint" }).notNull(),
|
|
3090
|
+
// Avg number of result rows
|
|
3091
|
+
prepared: mysqlCore.boolean("PREPARED").notNull(),
|
|
3092
|
+
// Whether statements are prepared
|
|
3093
|
+
avgAffectedRows: mysqlCore.double("AVG_AFFECTED_ROWS").notNull(),
|
|
3094
|
+
// Avg affected rows
|
|
3095
|
+
firstSeen: mysqlCore.timestamp("FIRST_SEEN", { mode: "string" }).notNull(),
|
|
3096
|
+
// First time statements observed
|
|
3097
|
+
lastSeen: mysqlCore.timestamp("LAST_SEEN", { mode: "string" }).notNull(),
|
|
3098
|
+
// Last time statements observed
|
|
3099
|
+
planInCache: mysqlCore.boolean("PLAN_IN_CACHE").notNull(),
|
|
3100
|
+
// Whether last stmt hit plan cache
|
|
3101
|
+
planCacheHits: mysqlCore.bigint("PLAN_CACHE_HITS", { mode: "bigint" }).notNull(),
|
|
3102
|
+
// Number of plan cache hits
|
|
3103
|
+
planInBinding: mysqlCore.boolean("PLAN_IN_BINDING").notNull(),
|
|
3104
|
+
// Whether matched bindings
|
|
3105
|
+
querySampleText: mysqlCore.text("QUERY_SAMPLE_TEXT"),
|
|
3106
|
+
// Sampled original SQL
|
|
3107
|
+
prevSampleText: mysqlCore.text("PREV_SAMPLE_TEXT"),
|
|
3108
|
+
// Sampled previous SQL before commit
|
|
3109
|
+
planDigest: mysqlCore.varchar("PLAN_DIGEST", { length: 64 }),
|
|
3110
|
+
// Plan digest hash
|
|
3111
|
+
plan: mysqlCore.text("PLAN"),
|
|
3112
|
+
// Sampled textual plan
|
|
3113
|
+
binaryPlan: mysqlCore.text("BINARY_PLAN"),
|
|
3114
|
+
// Sampled binary plan
|
|
3115
|
+
charset: mysqlCore.varchar("CHARSET", { length: 64 }),
|
|
3116
|
+
// Sampled charset
|
|
3117
|
+
collation: mysqlCore.varchar("COLLATION", { length: 64 }),
|
|
3118
|
+
// Sampled collation
|
|
3119
|
+
planHint: mysqlCore.varchar("PLAN_HINT", { length: 64 }),
|
|
3120
|
+
// Sampled plan hint
|
|
3121
|
+
maxRequestUnitRead: mysqlCore.double("MAX_REQUEST_UNIT_READ").notNull(),
|
|
3122
|
+
// Max RU cost (read)
|
|
3123
|
+
avgRequestUnitRead: mysqlCore.double("AVG_REQUEST_UNIT_READ").notNull(),
|
|
3124
|
+
// Avg RU cost (read)
|
|
3125
|
+
maxRequestUnitWrite: mysqlCore.double("MAX_REQUEST_UNIT_WRITE").notNull(),
|
|
3126
|
+
// Max RU cost (write)
|
|
3127
|
+
avgRequestUnitWrite: mysqlCore.double("AVG_REQUEST_UNIT_WRITE").notNull(),
|
|
3128
|
+
// Avg RU cost (write)
|
|
3129
|
+
maxQueuedRcTime: mysqlCore.bigint("MAX_QUEUED_RC_TIME", { mode: "bigint", unsigned: true }).notNull(),
|
|
3130
|
+
// Max queued time waiting for RU (ns)
|
|
3131
|
+
avgQueuedRcTime: mysqlCore.bigint("AVG_QUEUED_RC_TIME", { mode: "bigint", unsigned: true }).notNull(),
|
|
3132
|
+
// Avg queued time waiting for RU (ns)
|
|
3133
|
+
resourceGroup: mysqlCore.varchar("RESOURCE_GROUP", { length: 64 }),
|
|
3134
|
+
// Bound resource group name
|
|
3135
|
+
planCacheUnqualified: mysqlCore.bigint("PLAN_CACHE_UNQUALIFIED", { mode: "bigint" }).notNull(),
|
|
3136
|
+
// Times not eligible for plan cache
|
|
3137
|
+
planCacheUnqualifiedLastReason: mysqlCore.text("PLAN_CACHE_UNQUALIFIED_LAST_REASON")
|
|
3138
|
+
// Last reason of plan cache ineligibility
|
|
3139
|
+
});
|
|
3140
|
+
const clusterStatementsSummaryHistory = informationSchema.table(
|
|
3141
|
+
"CLUSTER_STATEMENTS_SUMMARY_HISTORY",
|
|
3142
|
+
createClusterStatementsSummarySchema()
|
|
3143
|
+
);
|
|
3144
|
+
const clusterStatementsSummary = informationSchema.table(
|
|
3145
|
+
"CLUSTER_STATEMENTS_SUMMARY",
|
|
3146
|
+
createClusterStatementsSummarySchema()
|
|
3147
|
+
);
|
|
2645
3148
|
async function getTables() {
|
|
2646
3149
|
const tables = await sql$1.sql.executeDDL("SHOW TABLES");
|
|
2647
3150
|
return tables.rows.flatMap((tableInfo) => Object.values(tableInfo));
|
|
@@ -2692,13 +3195,13 @@ const applySchemaMigrations = async (migration) => {
|
|
|
2692
3195
|
body: "Migrations successfully executed"
|
|
2693
3196
|
};
|
|
2694
3197
|
} catch (error) {
|
|
2695
|
-
const errorMessage = error?.debug?.sqlMessage ?? error?.debug?.message ?? error.message ?? "Unknown error occurred";
|
|
3198
|
+
const errorMessage = error?.cause?.context?.debug?.sqlMessage ?? error?.cause?.context?.debug?.message ?? error?.debug?.context?.sqlMessage ?? error?.debug?.context?.message ?? error.message ?? "Unknown error occurred";
|
|
2696
3199
|
console.error("Error during migration:", errorMessage);
|
|
2697
3200
|
return {
|
|
2698
3201
|
headers: { "Content-Type": ["application/json"] },
|
|
2699
3202
|
statusCode: 500,
|
|
2700
3203
|
statusText: "Internal Server Error",
|
|
2701
|
-
body: error instanceof Error ?
|
|
3204
|
+
body: error instanceof Error ? errorMessage : "Unknown error during migration"
|
|
2702
3205
|
};
|
|
2703
3206
|
}
|
|
2704
3207
|
};
|
|
@@ -2789,6 +3292,200 @@ const clearCacheSchedulerTrigger = async (options) => {
|
|
|
2789
3292
|
};
|
|
2790
3293
|
}
|
|
2791
3294
|
};
|
|
3295
|
+
const DEFAULT_MEMORY_THRESHOLD = 8 * 1024 * 1024;
|
|
3296
|
+
const DEFAULT_TIMEOUT = 300;
|
|
3297
|
+
const topSlowestStatementLastHourTrigger = async (orm, options) => {
|
|
3298
|
+
if (!orm) {
|
|
3299
|
+
return {
|
|
3300
|
+
statusCode: 500,
|
|
3301
|
+
headers: { "Content-Type": ["application/json"] },
|
|
3302
|
+
body: JSON.stringify({
|
|
3303
|
+
success: false,
|
|
3304
|
+
message: "ORM instance is required",
|
|
3305
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
3306
|
+
})
|
|
3307
|
+
};
|
|
3308
|
+
}
|
|
3309
|
+
let newOptions = options ?? {
|
|
3310
|
+
warnThresholdMs: DEFAULT_TIMEOUT,
|
|
3311
|
+
memoryThresholdBytes: DEFAULT_MEMORY_THRESHOLD,
|
|
3312
|
+
showPlan: false
|
|
3313
|
+
};
|
|
3314
|
+
const nsToMs = (v) => {
|
|
3315
|
+
const n = Number(v);
|
|
3316
|
+
return Number.isFinite(n) ? n / 1e6 : NaN;
|
|
3317
|
+
};
|
|
3318
|
+
const bytesToMB = (v) => {
|
|
3319
|
+
const n = Number(v);
|
|
3320
|
+
return Number.isFinite(n) ? n / (1024 * 1024) : NaN;
|
|
3321
|
+
};
|
|
3322
|
+
const jsonSafeStringify = (value) => JSON.stringify(value, (_k, v) => typeof v === "bigint" ? v.toString() : v);
|
|
3323
|
+
function sanitizeSQL(sql2, maxLen = 1e3) {
|
|
3324
|
+
let s = sql2;
|
|
3325
|
+
s = s.replace(/--[^\n\r]*/g, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
3326
|
+
s = s.replace(/'(?:\\'|[^'])*'/g, "?");
|
|
3327
|
+
s = s.replace(/\b-?\d+(?:\.\d+)?\b/g, "?");
|
|
3328
|
+
s = s.replace(/\s+/g, " ").trim();
|
|
3329
|
+
if (s.length > maxLen) {
|
|
3330
|
+
s = s.slice(0, maxLen) + " …[truncated]";
|
|
3331
|
+
}
|
|
3332
|
+
return s;
|
|
3333
|
+
}
|
|
3334
|
+
const TOP_N = 1;
|
|
3335
|
+
try {
|
|
3336
|
+
const summaryHistory = clusterStatementsSummaryHistory;
|
|
3337
|
+
const summary = clusterStatementsSummary;
|
|
3338
|
+
const selectShape = (t) => ({
|
|
3339
|
+
digest: t.digest,
|
|
3340
|
+
stmtType: t.stmtType,
|
|
3341
|
+
schemaName: t.schemaName,
|
|
3342
|
+
execCount: t.execCount,
|
|
3343
|
+
avgLatencyNs: t.avgLatency,
|
|
3344
|
+
maxLatencyNs: t.maxLatency,
|
|
3345
|
+
minLatencyNs: t.minLatency,
|
|
3346
|
+
avgProcessTimeNs: t.avgProcessTime,
|
|
3347
|
+
avgWaitTimeNs: t.avgWaitTime,
|
|
3348
|
+
avgBackoffTimeNs: t.avgBackoffTime,
|
|
3349
|
+
avgTotalKeys: t.avgTotalKeys,
|
|
3350
|
+
firstSeen: t.firstSeen,
|
|
3351
|
+
lastSeen: t.lastSeen,
|
|
3352
|
+
planInCache: t.planInCache,
|
|
3353
|
+
planCacheHits: t.planCacheHits,
|
|
3354
|
+
digestText: t.digestText,
|
|
3355
|
+
plan: t.plan,
|
|
3356
|
+
avgMemBytes: t.avgMem,
|
|
3357
|
+
maxMemBytes: t.maxMem
|
|
3358
|
+
});
|
|
3359
|
+
const lastHourFilterHistory = drizzleOrm.gte(
|
|
3360
|
+
summaryHistory.summaryEndTime,
|
|
3361
|
+
drizzleOrm.sql`DATE_SUB(NOW(), INTERVAL 1 HOUR)`
|
|
3362
|
+
);
|
|
3363
|
+
const lastHourFilterSummary = drizzleOrm.gte(
|
|
3364
|
+
summary.summaryEndTime,
|
|
3365
|
+
drizzleOrm.sql`DATE_SUB(NOW(), INTERVAL 1 HOUR)`
|
|
3366
|
+
);
|
|
3367
|
+
const qHistory = orm.getDrizzleQueryBuilder().select(selectShape(summaryHistory)).from(summaryHistory).where(lastHourFilterHistory);
|
|
3368
|
+
const qSummary = orm.getDrizzleQueryBuilder().select(selectShape(summary)).from(summary).where(lastHourFilterSummary);
|
|
3369
|
+
const combined = mysqlCore.unionAll(qHistory, qSummary).as("combined");
|
|
3370
|
+
const thresholdNs = Math.floor((newOptions.warnThresholdMs ?? DEFAULT_TIMEOUT) * 1e6);
|
|
3371
|
+
const memoryThresholdBytes = newOptions.memoryThresholdBytes ?? DEFAULT_MEMORY_THRESHOLD;
|
|
3372
|
+
const grouped = orm.getDrizzleQueryBuilder().select({
|
|
3373
|
+
digest: combined.digest,
|
|
3374
|
+
stmtType: combined.stmtType,
|
|
3375
|
+
schemaName: combined.schemaName,
|
|
3376
|
+
execCount: drizzleOrm.sql`SUM(${combined.execCount})`.as("execCount"),
|
|
3377
|
+
avgLatencyNs: drizzleOrm.sql`MAX(${combined.avgLatencyNs})`.as("avgLatencyNs"),
|
|
3378
|
+
maxLatencyNs: drizzleOrm.sql`MAX(${combined.maxLatencyNs})`.as("maxLatencyNs"),
|
|
3379
|
+
minLatencyNs: drizzleOrm.sql`MIN(${combined.minLatencyNs})`.as("minLatencyNs"),
|
|
3380
|
+
avgProcessTimeNs: drizzleOrm.sql`MAX(${combined.avgProcessTimeNs})`.as("avgProcessTimeNs"),
|
|
3381
|
+
avgWaitTimeNs: drizzleOrm.sql`MAX(${combined.avgWaitTimeNs})`.as("avgWaitTimeNs"),
|
|
3382
|
+
avgBackoffTimeNs: drizzleOrm.sql`MAX(${combined.avgBackoffTimeNs})`.as("avgBackoffTimeNs"),
|
|
3383
|
+
avgMemBytes: drizzleOrm.sql`MAX(${combined.avgMemBytes})`.as("avgMemBytes"),
|
|
3384
|
+
maxMemBytes: drizzleOrm.sql`MAX(${combined.maxMemBytes})`.as("maxMemBytes"),
|
|
3385
|
+
avgTotalKeys: drizzleOrm.sql`MAX(${combined.avgTotalKeys})`.as("avgTotalKeys"),
|
|
3386
|
+
firstSeen: drizzleOrm.sql`MIN(${combined.firstSeen})`.as("firstSeen"),
|
|
3387
|
+
lastSeen: drizzleOrm.sql`MAX(${combined.lastSeen})`.as("lastSeen"),
|
|
3388
|
+
planInCache: drizzleOrm.sql`MAX(${combined.planInCache})`.as("planInCache"),
|
|
3389
|
+
planCacheHits: drizzleOrm.sql`SUM(${combined.planCacheHits})`.as("planCacheHits"),
|
|
3390
|
+
// Prefer a non-empty sample text/plan via MAX; acceptable for de-dup
|
|
3391
|
+
digestText: drizzleOrm.sql`MAX(${combined.digestText})`.as("digestText"),
|
|
3392
|
+
plan: drizzleOrm.sql`MAX(${combined.plan})`.as("plan")
|
|
3393
|
+
}).from(combined).where(
|
|
3394
|
+
drizzleOrm.sql`COALESCE(${combined.digest}, '') <> '' AND COALESCE(${combined.digestText}, '') <> '' AND COALESCE(${combined.stmtType}, '') NOT IN ('Use','Set','Show')`
|
|
3395
|
+
).groupBy(combined.digest, combined.stmtType, combined.schemaName).as("grouped");
|
|
3396
|
+
const rows = await orm.getDrizzleQueryBuilder().select({
|
|
3397
|
+
digest: grouped.digest,
|
|
3398
|
+
stmtType: grouped.stmtType,
|
|
3399
|
+
schemaName: grouped.schemaName,
|
|
3400
|
+
execCount: grouped.execCount,
|
|
3401
|
+
avgLatencyNs: grouped.avgLatencyNs,
|
|
3402
|
+
maxLatencyNs: grouped.maxLatencyNs,
|
|
3403
|
+
minLatencyNs: grouped.minLatencyNs,
|
|
3404
|
+
avgProcessTimeNs: grouped.avgProcessTimeNs,
|
|
3405
|
+
avgWaitTimeNs: grouped.avgWaitTimeNs,
|
|
3406
|
+
avgBackoffTimeNs: grouped.avgBackoffTimeNs,
|
|
3407
|
+
avgMemBytes: grouped.avgMemBytes,
|
|
3408
|
+
maxMemBytes: grouped.maxMemBytes,
|
|
3409
|
+
avgTotalKeys: grouped.avgTotalKeys,
|
|
3410
|
+
firstSeen: grouped.firstSeen,
|
|
3411
|
+
lastSeen: grouped.lastSeen,
|
|
3412
|
+
planInCache: grouped.planInCache,
|
|
3413
|
+
planCacheHits: grouped.planCacheHits,
|
|
3414
|
+
digestText: grouped.digestText,
|
|
3415
|
+
plan: grouped.plan
|
|
3416
|
+
}).from(grouped).where(
|
|
3417
|
+
drizzleOrm.sql`${grouped.avgLatencyNs} > ${thresholdNs} OR ${grouped.avgMemBytes} > ${memoryThresholdBytes}`
|
|
3418
|
+
).orderBy(drizzleOrm.desc(grouped.avgLatencyNs)).limit(formatLimitOffset(TOP_N));
|
|
3419
|
+
const formatted = rows.map((r, i) => ({
|
|
3420
|
+
rank: i + 1,
|
|
3421
|
+
// 1-based rank in the top N
|
|
3422
|
+
digest: r.digest,
|
|
3423
|
+
stmtType: r.stmtType,
|
|
3424
|
+
schemaName: r.schemaName,
|
|
3425
|
+
execCount: r.execCount,
|
|
3426
|
+
avgLatencyMs: nsToMs(r.avgLatencyNs),
|
|
3427
|
+
// Convert ns to ms for readability
|
|
3428
|
+
maxLatencyMs: nsToMs(r.maxLatencyNs),
|
|
3429
|
+
minLatencyMs: nsToMs(r.minLatencyNs),
|
|
3430
|
+
avgProcessTimeMs: nsToMs(r.avgProcessTimeNs),
|
|
3431
|
+
avgWaitTimeMs: nsToMs(r.avgWaitTimeNs),
|
|
3432
|
+
avgBackoffTimeMs: nsToMs(r.avgBackoffTimeNs),
|
|
3433
|
+
avgMemMB: bytesToMB(r.avgMemBytes),
|
|
3434
|
+
maxMemMB: bytesToMB(r.maxMemBytes),
|
|
3435
|
+
avgMemBytes: r.avgMemBytes,
|
|
3436
|
+
maxMemBytes: r.maxMemBytes,
|
|
3437
|
+
avgTotalKeys: r.avgTotalKeys,
|
|
3438
|
+
firstSeen: r.firstSeen,
|
|
3439
|
+
lastSeen: r.lastSeen,
|
|
3440
|
+
planInCache: r.planInCache,
|
|
3441
|
+
planCacheHits: r.planCacheHits,
|
|
3442
|
+
digestText: sanitizeSQL(r.digestText),
|
|
3443
|
+
plan: newOptions.showPlan ? r.plan : void 0
|
|
3444
|
+
}));
|
|
3445
|
+
for (const f of formatted) {
|
|
3446
|
+
console.warn(
|
|
3447
|
+
`${f.rank}. ${f.stmtType} avg=${f.avgLatencyMs?.toFixed?.(2)}ms max=${f.maxLatencyMs?.toFixed?.(2)}ms mem≈${f.avgMemMB?.toFixed?.(2)}MB(max ${f.maxMemMB?.toFixed?.(2)}MB) exec=${f.execCount}
|
|
3448
|
+
digest=${f.digest}
|
|
3449
|
+
sql=${(f.digestText || "").slice(0, 300)}${f.digestText && f.digestText.length > 300 ? "…" : ""}`
|
|
3450
|
+
);
|
|
3451
|
+
if (newOptions.showPlan && f.plan) {
|
|
3452
|
+
console.warn(` full plan:
|
|
3453
|
+
${f.plan}`);
|
|
3454
|
+
}
|
|
3455
|
+
}
|
|
3456
|
+
return {
|
|
3457
|
+
headers: { "Content-Type": ["application/json"] },
|
|
3458
|
+
statusCode: 200,
|
|
3459
|
+
statusText: "OK",
|
|
3460
|
+
body: jsonSafeStringify({
|
|
3461
|
+
success: true,
|
|
3462
|
+
window: "last_1h",
|
|
3463
|
+
top: TOP_N,
|
|
3464
|
+
warnThresholdMs: newOptions.warnThresholdMs,
|
|
3465
|
+
memoryThresholdBytes: newOptions.memoryThresholdBytes,
|
|
3466
|
+
showPlan: newOptions.showPlan,
|
|
3467
|
+
rows: formatted,
|
|
3468
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3469
|
+
})
|
|
3470
|
+
};
|
|
3471
|
+
} catch (error) {
|
|
3472
|
+
console.error(
|
|
3473
|
+
"Error in topSlowestStatementLastHourTrigger:",
|
|
3474
|
+
error?.cause?.context?.debug?.sqlMessage ?? error?.cause ?? error
|
|
3475
|
+
);
|
|
3476
|
+
return {
|
|
3477
|
+
headers: { "Content-Type": ["application/json"] },
|
|
3478
|
+
statusCode: 500,
|
|
3479
|
+
statusText: "Internal Server Error",
|
|
3480
|
+
body: jsonSafeStringify({
|
|
3481
|
+
success: false,
|
|
3482
|
+
message: "Failed to fetch or log slow queries",
|
|
3483
|
+
error: error?.cause?.context?.debug?.sqlMessage ?? error?.cause?.message,
|
|
3484
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
3485
|
+
})
|
|
3486
|
+
};
|
|
3487
|
+
}
|
|
3488
|
+
};
|
|
2792
3489
|
const getHttpResponse = (statusCode, body) => {
|
|
2793
3490
|
let statusText = "";
|
|
2794
3491
|
if (statusCode === 200) {
|
|
@@ -2808,6 +3505,8 @@ exports.ForgeSQLSelectOperations = ForgeSQLSelectOperations;
|
|
|
2808
3505
|
exports.applyFromDriverTransform = applyFromDriverTransform;
|
|
2809
3506
|
exports.applySchemaMigrations = applySchemaMigrations;
|
|
2810
3507
|
exports.clearCacheSchedulerTrigger = clearCacheSchedulerTrigger;
|
|
3508
|
+
exports.clusterStatementsSummary = clusterStatementsSummary;
|
|
3509
|
+
exports.clusterStatementsSummaryHistory = clusterStatementsSummaryHistory;
|
|
2811
3510
|
exports.default = ForgeSQLORM;
|
|
2812
3511
|
exports.dropSchemaMigrations = dropSchemaMigrations;
|
|
2813
3512
|
exports.dropTableSchemaMigrations = dropTableSchemaMigrations;
|
|
@@ -2831,4 +3530,6 @@ exports.migrations = migrations;
|
|
|
2831
3530
|
exports.nextVal = nextVal;
|
|
2832
3531
|
exports.parseDateTime = parseDateTime;
|
|
2833
3532
|
exports.patchDbWithSelectAliased = patchDbWithSelectAliased;
|
|
3533
|
+
exports.slowQuery = slowQuery;
|
|
3534
|
+
exports.topSlowestStatementLastHourTrigger = topSlowestStatementLastHourTrigger;
|
|
2834
3535
|
//# sourceMappingURL=ForgeSQLORM.js.map
|