@cryptotaxi247 / netdata-1 / commits / 0398c6cff

Update statistics to address slow queries (#16838)

* Run analyze on aclk_alert tables Add analyze option -W sqlite-analyze * Remove empty line * Remove analyze during runtime * Remove health_log_entries_written * Replace index * Remove forced index skip * Change version and run database analyze * Adjust analyze to run on specific tables Fix previous migration v14 -> v15 typo * Fix v15 -> v16 migration message * Fix v15 -> v16 migration message (typo) * Increase analysis limit

Stelios Fragkakis committed Jan 29, 2024 at 15:36 UTC 0398c6cff4d611eb53d923d7f464e0ce15ceba9e
7 files changed +67 -64
daemon/main.c
+6
@@ -812,6 +812,7 @@ int help(int exitcode) {
812 " -W unittest Run internal unittests and exit.\n\n"
813 " -W sqlite-meta-recover Run recovery on the metadata database and exit.\n\n"
814 " -W sqlite-compact Reclaim metadata database unused space and exit.\n\n"
815 + " -W sqlite-analyze Run update statistics and exit.\n\n"
816 #ifdef ENABLE_DBENGINE
817 " -W createdataset=N Create a DB engine dataset of N seconds and exit.\n\n"
818 " -W stresstest=A,B,C,D,E,F,G\n"
@@ -1528,6 +1529,11 @@ int main(int argc, char **argv) {
1529 return 0;
1530 }
1531
1532 + if(strcmp(optarg, "sqlite-analyze") == 0) {
1533 + sql_init_database(DB_CHECK_ANALYZE, 0);
1534 + return 0;
1535 + }
1536 +
1537 if(strcmp(optarg, "unittest") == 0) {
1538 unittest_running = true;
1539
database/rrd.h
-1
@@ -1093,7 +1093,6 @@ typedef struct health {
1093 time_t health_delay_up_to; // a timestamp to delay alarms processing up to
1094 STRING *health_default_exec; // the full path of the alarms notifications program
1095 STRING *health_default_recipient; // the default recipient for all alarms
1096 - int health_log_entries_written; // the number of alarm events written to the alarms event log
1096 uint32_t health_default_warn_repeat_every; // the default value for the interval between repeating warning notifications
1097 uint32_t health_default_crit_repeat_every; // the default value for the interval between repeating critical notifications
1098 unsigned int health_enabled; // 1 when this host has health enabled
database/sqlite/sqlite_aclk_alert.c
+1 -1
@@ -97,7 +97,7 @@ done:
97 //decide if some events should be sent or not
98 #define SQL_SELECT_ALERT_BY_ID \
99 "SELECT hld.new_status, hl.config_hash_id, hld.unique_id FROM health_log hl, aclk_alert_%s aa, health_log_detail hld " \
100 - "WHERE hl.host_id = @host_id AND +hld.unique_id = aa.filtered_alert_unique_id " \
100 + "WHERE hl.host_id = @host_id AND hld.unique_id = aa.filtered_alert_unique_id " \
101 "AND hld.alarm_id = @alarm_id AND hl.health_log_id = hld.health_log_id " \
102 "ORDER BY hld.rowid DESC LIMIT 1"
103
database/sqlite/sqlite_db_migration.c
+39 -3
@@ -382,14 +382,49 @@ static int do_migration_v14_v15(sqlite3 *database)
382 }
383
384 BUFFER *wb = buffer_create(128, NULL);
385 - while (sqlite3_step_monitored(res) == SQLITE_ROW)
386 - buffer_sprintf(wb, "DROP INDEX IF EXISTS %s", (char *) sqlite3_column_text(res, 0));
385 + size_t count = 0;
386 + while (sqlite3_step_monitored(res) == SQLITE_ROW) {
387 + buffer_sprintf(wb, "DROP INDEX IF EXISTS %s; ", (char *)sqlite3_column_text(res, 0));
388 + count++;
389 + }
390
391 rc = sqlite3_finalize(res);
392 if (unlikely(rc != SQLITE_OK))
393 error_report("Failed to finalize statement when dropping unused indices, rc = %d", rc);
394
392 - (void) db_execute(database, buffer_tostring(wb));
395 + if (count)
396 + (void) db_execute(database, buffer_tostring(wb));
397 +
398 + buffer_free(wb);
399 + return 0;
400 +}
401 +
402 +static int do_migration_v15_v16(sqlite3 *database)
403 +{
404 + char sql[256];
405 +
406 + int rc;
407 + sqlite3_stmt *res = NULL;
408 + snprintfz(sql, sizeof(sql) - 1, "SELECT name FROM sqlite_schema WHERE type = \"table\" AND name LIKE \"aclk_alert_%%\"");
409 + rc = sqlite3_prepare_v2(database, sql, -1, &res, 0);
410 + if (rc != SQLITE_OK) {
411 + error_report("Failed to prepare statement to drop unused indices");
412 + return 1;
413 + }
414 +
415 + BUFFER *wb = buffer_create(128, NULL);
416 + size_t count = 0;
417 + while (sqlite3_step_monitored(res) == SQLITE_ROW) {
418 + buffer_sprintf(wb, "ANALYZE %s ; ", (char *)sqlite3_column_text(res, 0));
419 + count++;
420 + }
421 +
422 + rc = sqlite3_finalize(res);
423 + if (unlikely(rc != SQLITE_OK))
424 + error_report("Failed to finalize statement when running ANALYZE on aclk_alert_tables, rc = %d", rc);
425 +
426 + if (count)
427 + (void) db_execute(database, buffer_tostring(wb));
428
429 buffer_free(wb);
430 return 0;
@@ -491,6 +526,7 @@ DATABASE_FUNC_MIGRATION_LIST migration_action[] = {
526 {.name = "v12 to v13", .func = do_migration_v12_v13},
527 {.name = "v13 to v14", .func = do_migration_v13_v14},
528 {.name = "v14 to v15", .func = do_migration_v14_v15},
529 + {.name = "v15 to v16", .func = do_migration_v15_v16},
530 // the terminator of this array
531 {.name = NULL, .func = NULL}
532 };
database/sqlite/sqlite_functions.c
+18 -3
@@ -4,7 +4,7 @@
4 #include "sqlite3recover.h"
5 #include "sqlite_db_migration.h"
6
7 -#define DB_METADATA_VERSION 15
7 +#define DB_METADATA_VERSION 16
8
9 const char *database_config[] = {
10 "CREATE TABLE IF NOT EXISTS host(host_id BLOB PRIMARY KEY, hostname TEXT NOT NULL, "
@@ -64,7 +64,7 @@ const char *database_config[] = {
64
65 "CREATE INDEX IF NOT EXISTS health_log_d_ind_2 ON health_log_detail (global_id)",
66 "CREATE INDEX IF NOT EXISTS health_log_d_ind_3 ON health_log_detail (transition_id)",
67 - "CREATE INDEX IF NOT EXISTS health_log_d_ind_5 ON health_log_detail (health_log_id, unique_id DESC)",
67 + "CREATE INDEX IF NOT EXISTS health_log_d_ind_9 ON health_log_detail (unique_id DESC, health_log_id)",
68 "CREATE INDEX IF NOT EXISTS health_log_d_ind_6 on health_log_detail (health_log_id, when_key)",
69 "CREATE INDEX IF NOT EXISTS health_log_d_ind_7 on health_log_detail (alarm_id)",
70 "CREATE INDEX IF NOT EXISTS health_log_d_ind_8 on health_log_detail (new_status, updated_by_id)",
@@ -84,6 +84,7 @@ const char *database_cleanup[] = {
84 "DROP INDEX IF EXISTS alert_hash_index",
85 "DROP INDEX IF EXISTS health_log_d_ind_4",
86 "DROP INDEX IF EXISTS health_log_d_ind_1",
87 + "DROP INDEX IF EXISTS health_log_d_ind_5",
88 NULL
89 };
90
@@ -448,6 +449,20 @@ int sql_init_database(db_check_action_type_t rebuild, int memory)
449 return 1;
450 }
451
452 + if (rebuild & DB_CHECK_ANALYZE) {
453 + netdata_log_info("Running ANALYZE on %s", sqlite_database);
454 + rc = sqlite3_exec_monitored(db_meta, "ANALYZE", 0, 0, &err_msg);
455 + if (rc != SQLITE_OK) {
456 + error_report("Failed to execute ANALYZE rc = %d (%s)", rc, err_msg);
457 + sqlite3_free(err_msg);
458 + }
459 + else {
460 + (void) db_execute(db_meta, "select count(*) from sqlite_master limit 0");
461 + (void) sqlite3_close(db_meta);
462 + }
463 + return 1;
464 + }
465 +
466 netdata_log_info("SQLite database %s initialization", sqlite_database);
467
468 rc = sqlite3_create_function(db_meta, "u2h", 1, SQLITE_ANY | SQLITE_DETERMINISTIC, 0, sqlite_uuid_parse, 0, 0);
@@ -497,7 +512,7 @@ void sql_close_database(void)
512
513 add_stmt_to_list(NULL);
514
500 - (void) db_execute(db_meta, "PRAGMA analysis_limit=1000");
515 + (void) db_execute(db_meta, "PRAGMA analysis_limit=10000");
516 (void) db_execute(db_meta, "PRAGMA optimize");
517
518 rc = sqlite3_close_v2(db_meta);
database/sqlite/sqlite_functions.h
+3 -2
@@ -21,8 +21,9 @@ struct node_instance_list {
21 typedef enum db_check_action_type {
22 DB_CHECK_NONE = (1 << 0),
23 DB_CHECK_RECLAIM_SPACE = (1 << 1),
24 - DB_CHECK_CONT = (1 << 2),
25 - DB_CHECK_RECOVER = (1 << 3),
24 + DB_CHECK_ANALYZE = (1 << 2),
25 + DB_CHECK_CONT = (1 << 3),
26 + DB_CHECK_RECOVER = (1 << 4),
27 } db_check_action_type_t;
28
29 #define SQL_MAX_RETRY (100)
database/sqlite/sqlite_health.c
-54
@@ -359,7 +359,6 @@ static void sql_health_alarm_log_insert(RRDHOST *host, ALARM_ENTRY *ae) {
359 }
360
361 ae->flags |= HEALTH_ENTRY_FLAG_SAVED;
362 - host->health.health_log_entries_written++;
362
363 failed:
364 if (unlikely(sqlite3_finalize(res) != SQLITE_OK))
@@ -380,48 +379,6 @@ void sql_health_alarm_log_save(RRDHOST *host, ALARM_ENTRY *ae)
379 }
380 }
381
383 -/* Health related SQL queries
384 - Get a count of rows from health log table
385 -*/
386 -#define SQL_COUNT_HEALTH_LOG_DETAIL "SELECT count(1) FROM health_log_detail hld, health_log hl " \
387 - "where hl.host_id = @host_id and hl.health_log_id = hld.health_log_id"
388 -
389 -static int sql_health_alarm_log_count(RRDHOST *host) {
390 - sqlite3_stmt *res = NULL;
391 - int rc;
392 -
393 - if (unlikely(!db_meta)) {
394 - if (default_rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE)
395 - error_report("Database has not been initialized");
396 - return -1;
397 - }
398 -
399 - int entries_in_db = -1;
400 -
401 - rc = sqlite3_prepare_v2(db_meta, SQL_COUNT_HEALTH_LOG_DETAIL, -1, &res, 0);
402 - if (unlikely(rc != SQLITE_OK)) {
403 - error_report("Failed to prepare statement to count health log entries from db");
404 - goto done;
405 - }
406 -
407 - rc = sqlite3_bind_blob(res, 1, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC);
408 - if (unlikely(rc != SQLITE_OK)) {
409 - error_report("Failed to bind host_id for SQL_COUNT_HEALTH_LOG.");
410 - goto done;
411 - }
412 -
413 - rc = sqlite3_step_monitored(res);
414 - if (likely(rc == SQLITE_ROW))
415 - entries_in_db = (int) sqlite3_column_int64(res, 0);
416 -
417 -done:
418 - rc = sqlite3_finalize(res);
419 - if (unlikely(rc != SQLITE_OK))
420 - error_report("Failed to finalize the prepared statement to count health log entries from db");
421 -
422 - return entries_in_db;
423 -}
424 -
382 /*
383 *
384 * Health related SQL queries
@@ -492,10 +449,6 @@ void sql_health_alarm_log_cleanup(RRDHOST *host, bool claimed) {
449 if (unlikely(rc != SQLITE_DONE))
450 error_report("Failed to cleanup health log detail table, rc = %d", rc);
451
495 - int rows = sql_health_alarm_log_count(host);
496 - if (rows >= 0)
497 - host->health.health_log_entries_written = rows;
498 -
452 if (aclk_table_exists)
453 sql_aclk_alert_clean_dead_entries(host);
454
@@ -769,8 +722,6 @@ void sql_health_alarm_log_load(RRDHOST *host)
722 int ret;
723 ssize_t errored = 0, loaded = 0;
724
772 - host->health.health_log_entries_written = 0;
773 -
725 if (unlikely(!db_meta)) {
726 if (default_rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE)
727 error_report("HEALTH [%s]: Database has not been initialized", rrdhost_hostname(host));
@@ -939,11 +890,6 @@ void sql_health_alarm_log_load(RRDHOST *host)
890 ret = sqlite3_finalize(res);
891 if (unlikely(ret != SQLITE_OK))
892 error_report("Failed to finalize the health log read statement");
942 -
943 - int rows = sql_health_alarm_log_count(host);
944 -
945 - if (rows >= 0)
946 - host->health.health_log_entries_written = rows;
893 }
894
895 /*