Slow query on mdl_user_private_key requiring index ================================================== The following query appears as part of the mdl_user select statements list in New Relic and appear in the slowest queries list. It's an infrequent visitor to the MySQL slow queries file, likely only when the system is already slow but the timings in New Relic indicate this as very slow for a query that is called frequently. SELECT u.id FROM mdl_user u JOIN mdl_user_private_key k ON u.id = k.userid WHERE u.deleted = 0 AND u.confirmed = 1 AND u.suspended = 0 AND k.value = 'c70d6d9e51ed81702bdfd73626ded013'; Analysis (below) shows the query picks a very inefficient plan based on low cardinality indexes and concludes that we should add or change an indexing on mdl_user_private_key to speed the query up to an acceptable level. The index change turns this from a query making 1.7 million lookups to one that makes 3. TLDR ==== ALTER TABLE `mdl_user_private_key` ADD KEY `uon_mdl_userprivkey_val_ix` (`value`); Query DIGEST ============ Roughly 1000 calls p/w *************************** 8. row *************************** SCHEMA_NAME: --- DIGEST: 2c2372a08830e13294de2945db9127c39e8902fc245804fd5f1a0bc1ce581cf2 DIGEST_TEXT: SELECT `u` . `id` FROM `mdl_user` `u` JOIN `mdl_user_private_key` `k` ON `u` . `id` = `k` . `userid` WHERE `u` . `deleted` = ? AND `u` . `confirmed` = ? AND `u` . `suspended` = ? AND `k` . `value` = ? COUNT_STAR: 3136 SUM_TIMER_WAIT: 5571937556400000 MIN_TIMER_WAIT: 1518648340000 AVG_TIMER_WAIT: 1776765802000 MAX_TIMER_WAIT: 97247250938000 SUM_LOCK_TIME: 502206000000 SUM_ERRORS: 0 SUM_WARNINGS: 0 SUM_ROWS_AFFECTED: 0 SUM_ROWS_SENT: 3059 SUM_ROWS_EXAMINED: 2265522555 SUM_CREATED_TMP_DISK_TABLES: 0 SUM_CREATED_TMP_TABLES: 0 SUM_SELECT_FULL_JOIN: 0 SUM_SELECT_FULL_RANGE_JOIN: 0 SUM_SELECT_RANGE: 3136 SUM_SELECT_RANGE_CHECK: 0 SUM_SELECT_SCAN: 0 SUM_SORT_MERGE_PASSES: 0 SUM_SORT_RANGE: 0 SUM_SORT_ROWS: 0 SUM_SORT_SCAN: 0 SUM_NO_INDEX_USED: 0 SUM_NO_GOOD_INDEX_USED: 0 FIRST_SEEN: 2022-04-05 12:07:54.192328 LAST_SEEN: 2022-04-26 12:30:33.614701 QUANTILE_95: 1995262314968 QUANTILE_99: 2187761623949 QUANTILE_999: 20892961308540 QUERY_SAMPLE_TEXT: SELECT u.id FROM mdl_user u JOIN mdl_user_private_key k ON u.id = k.userid WHERE u.deleted = 0 AND u.confirmed = 1 AND u.suspended = 0 AND k.value = 'c70d6d9e51ed81702bdfd73626ded013' QUERY_SAMPLE_SEEN: 2022-04-26 12:30:33.614701 QUERY_SAMPLE_TIMER_WAIT: 1748779965000 8 rows in set (0.1999 sec) Example query Timings in slow log ================================= # Time: 2022-04-08T16:08:05.718431Z # User@Host: ---- # Query_time: 20.787225 Lock_time: 0.000164 Rows_sent: 1 Rows_examined: 722000 SET timestamp=1649434064; SELECT u.id FROM mdl_user u JOIN mdl_user_private_key k ON u.id = k.userid WHERE u.deleted = 0 AND u.confirmed = 1 AND u.suspended = 0 AND k.value = 'c70d6d9e51ed81702bdfd73626ded013'; # Time: 2022-04-08T16:17:50.312332Z # User@Host: --- # Query_time: 11.081137 Lock_time: 0.000165 Rows_sent: 1 Rows_examined: 722000 SET timestamp=1649434659; SELECT u.id FROM mdl_user u JOIN mdl_user_private_key k ON u.id = k.userid WHERE u.deleted = 0 AND u.confirmed = 1 AND u.suspended = 0 AND k.value = 'c70d6d9e51ed81702bdfd73626ded013'; -- NB -- Rows examined is the red flag here, private keys are by definition unique so you'd expect a point query on that value -- We have seen this query take over 10 minutes in LIVE, presumably there was another problem at the time that caused it to get hung up. MySQL SQL > show create table mdl_user_private_key\G *************************** 1. row *************************** Table: mdl_user_private_key Create Table: CREATE TABLE `mdl_user_private_key` ( `id` bigint NOT NULL AUTO_INCREMENT, `script` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', `value` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', `userid` bigint NOT NULL, `instance` bigint DEFAULT NULL, `iprestriction` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, `validuntil` bigint DEFAULT NULL, `timecreated` bigint DEFAULT NULL, PRIMARY KEY (`id`), KEY `mdl_userprivkey_scrval_ix` (`script`,`value`), <<<<<<<<<<<<<<<<<<< Query doesn't use this index KEY `mdl_userprivkey_use_ix` (`userid`) ) ENGINE=InnoDB AUTO_INCREMENT=660684 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='access keys used in cookieless scripts - rss, etc.' 1 row in set (0.0006 sec) -- `value` column can not be looked up directly because it is not left-most column in index `mdl_userprivkey_scrval_ix` MySQL SQL > show indexes from mdl_user_private_key; +----------------------+------------+---------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression | +----------------------+------------+---------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+ | mdl_user_private_key | 0 | PRIMARY | 1 | id | A | 432512 | NULL | NULL | | BTREE | | | YES | NULL | | mdl_user_private_key | 1 | mdl_userprivkey_scrval_ix | 1 | script | A | 2 | NULL | NULL | | BTREE | | | YES | NULL | | mdl_user_private_key | 1 | mdl_userprivkey_scrval_ix | 2 | value | A | 423500 | NULL | NULL | | BTREE | | | YES | NULL | | mdl_user_private_key | 1 | mdl_userprivkey_use_ix | 1 | userid | A | 252109 | NULL | NULL | | BTREE | | | YES | NULL | +----------------------+------------+---------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+ 4 rows in set (0.0439 sec) INDEX mdl_userprivkey_scrval_ix =============================== -- Shows low cardinality on `script` column (3 different values), high cardinality on `value` column -- There are arguments that you should put the LC part first in a composite key because it makes for a more balanced index -- Query doesn't include `script` column so index doesn't get used for the query. -- If the columns were reversed in the index it would be ideal for our purposes. -- How costly is it to find a single 'value'? MySQL SQL > EXPLAIN select count(*) from mdl_user_private_key where value = 'c70d6d9e51ed81702bdfd73626ded013'; +----+-------------+----------------------+------------+-------+---------------------------+---------------------------+---------+------+-------+----------+----------------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+----------------------+------------+-------+---------------------------+---------------------------+---------+------+-------+----------+----------------------------------------+ | 1 | SIMPLE | mdl_user_private_key | NULL | range | mdl_userprivkey_scrval_ix | mdl_userprivkey_scrval_ix | 1028 | NULL | 43402 | 100 | Using where; Using index for skip scan | +----+-------------+----------------------+------------+-------+---------------------------+---------------------------+---------+------+-------+----------+----------------------------------------+ 1 row in set (0.0009 sec) -- Interesting 'skip scan', that's a new optimization in v 8.0.12, tests for all values in first part of index, then looks up the second -- Estimates 43K rows read on a single lookup - but it's way more efficient than that MySQL SQL > show status like 'handler%'; +----------------------------+-------+ | Variable_name | Value | +----------------------------+-------+ | Handler_commit | 1 | | Handler_delete | 0 | | Handler_discover | 0 | | Handler_external_lock | 2 | | Handler_mrr_init | 0 | | Handler_prepare | 0 | | Handler_read_first | 1 | | Handler_read_key | 7 | <<<<<<< 'skip scan' optimization - not 43K rows | Handler_read_last | 0 | | Handler_read_next | 1 | | Handler_read_prev | 0 | | Handler_read_rnd | 0 | | Handler_read_rnd_next | 0 | | Handler_rollback | 0 | | Handler_savepoint | 0 | | Handler_savepoint_rollback | 0 | | Handler_update | 0 | | Handler_write | 0 | +----------------------------+-------+ 18 rows in set (0.0028 sec) -- How many rows with the 'value' we are checking? MySQL SQL > select count(*) from mdl_user_private_key where value = 'c70d6d9e51ed81702bdfd73626ded013'; +----------+ | count(*) | +----------+ | 1 | +----------+ 1 row in set (0.0017 sec) -- Just the one MySQL SQL > select count(*) from mdl_user_private_key; +----------+ | count(*) | +----------+ | 437246 | <<<<<<<< total rows +----------+ 1 row in set (0.0339 sec) -- How many have duplicates? MySQL SQL > select value, count(*) from mdl_user_private_key group by 1 having count(*) > 1; Empty set (0.6652 sec) <<<<<<<<<<<< This is the time to scan the table once (and write to temp file), so the query cost at 1.7 seconds MUST be doing multiple scans --there are NO duplicates in the table == -- THIS COULD (probably) BE A UNIQUE KEY MySQL SQL > EXPLAIN SELECT u.id FROM mdl_user u -> JOIN mdl_user_private_key k ON u.id = k.userid -> WHERE u.deleted = 0 AND u.confirmed = 1 -> AND u.suspended = 0 AND k.value = 'c70d6d9e51ed81702bdfd73626ded013'; +----+-------------+-------+------------+-------------+-----------------------------------------+---------------------------------+---------+-----------------+-------+----------+---------------------------------------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+-------------+-----------------------------------------+---------------------------------+---------+-----------------+-------+----------+---------------------------------------------------------------+ | 1 | SIMPLE | u | NULL | index_merge | PRIMARY,mdl_user_del_ix,mdl_user_con_ix | mdl_user_del_ix,mdl_user_con_ix | 1,1 | NULL | 76358 | 10 | Using intersect(mdl_user_del_ix,mdl_user_con_ix); Using where | | 1 | SIMPLE | k | NULL | ref | mdl_userprivkey_use_ix | mdl_userprivkey_use_ix | 8 | livemoodle.u.id | 1 | 10 | Using where | +----+-------------+-------+------------+-------------+-----------------------------------------+---------------------------------+---------+-----------------+-------+----------+---------------------------------------------------------------+ 2 rows in set (0.0794 sec) -- Uses index merge 'optimization' on mdl_user to find user rows then joins to mdl_private_key. -- Estimates 76K rows from mdl_user - actually nearer to 4x that. MySQL SQL > select count(*) from mdl_user where deleted = 0 and confirmed = 1; +----------+ | count(*) | +----------+ | 289615 | +----------+ 1 row in set (0.1541 sec) -- index_merge is a good access plan if all parts have high cardinality indexes - these aren't. -- ref on the second line of query EXPLAIN implies there may be more than one row in - this is a reasonable assumption -- the potential for a 'skip scan' on the point lookup on `value` in the where clause is not considered by the optimizer -- Starting in mdl_user_private_key is rejected, probably because `value` isn't first in index EXPLAIN ANALYZE =============== MySQL SQL > EXPLAIN ANALYZE SELECT u.id FROM mdl_user u JOIN mdl_user_private_key k ON u.id = k.userid WHERE u.deleted = 0 AND u.confirmed = 1 AND u.suspended = 0 AND k.value = 'c70d6d9e51ed81702bdfd73626ded013'; -> Nested loop inner join (cost=18972.57 rows=1314) (actual time=4816.585..6084.856 rows=1 loops=1) -> Filter: ((u.suspended = 0) and (u.confirmed = 1) and (u.deleted = 0)) (cost=14373.90 rows=7636) (actual time=19.388..2911.593 rows=285824 loops=1) -> Index range scan on u using intersect(mdl_user_del_ix,mdl_user_con_ix) (cost=14373.90 rows=76358) (actual time=19.379..2822.940 rows=289615 loops=1) -> Filter: (k.`value` = 'c70d6d9e51ed81702bdfd73626ded013') (cost=0.43 rows=0) (actual time=0.011..0.011 rows=0 loops=285824) -> Index lookup on k using mdl_userprivkey_use_ix (userid=u.id) (cost=0.43 rows=2) (actual time=0.010..0.010 rows=2 loops=285824) 1 row in set (6.0919 sec) RUNNING CURRENT =============== MySQL SQL > SELECT u.id FROM mdl_user u JOIN mdl_user_private_key k ON u.id = k.userid WHERE u.deleted = 0 AND u.confirmed = 1 AND u.suspended = 0 AND k.value = 'c70d6d9e51ed81702bdfd73626ded013'; +--------+ | id | +--------+ | 242313 | +--------+ 1 row in set (1.7772 sec) <<<<<<<<<<<<<<<<<< Per query time -- It does a LOT of work to get the one userid MySQL SQL > show status like 'handler%'; +----------------------------+---------+ | Variable_name | Value | +----------------------------+---------+ | Handler_commit | 1 | | Handler_delete | 0 | | Handler_discover | 0 | | Handler_external_lock | 8 | | Handler_mrr_init | 0 | | Handler_prepare | 0 | | Handler_read_first | 0 | | Handler_read_key | 575441 | <<<<<<< Rows retieved to check on non-indexed `suspended` column in where clause, i.e. it considers the same PK values twice | Handler_read_last | 0 | | Handler_read_next | 1033118 | <<<<<<< Index scans on low cardinality cols | Handler_read_prev | 0 | | Handler_read_rnd | 289615 | <<<<<<< eventually reads these table rows via PK | Handler_read_rnd_next | 0 | | Handler_rollback | 0 | | Handler_savepoint | 0 | | Handler_savepoint_rollback | 0 | | Handler_update | 0 | | Handler_write | 0 | +----------------------------+---------+ 18 rows in set (0.0027 sec) -- Implies multiple scans over the chosen indexes, retrieve join record via userid key, 1.7 million lookups in total MySQL SQL > show profile for query 3; +--------------------------------+----------+ | Status | Duration | +--------------------------------+----------+ | starting | 0.000175 | | Executing hook on transaction | 0.000030 | | starting | 0.000025 | | checking permissions | 0.000023 | | checking permissions | 0.006078 | | Opening tables | 0.000118 | | init | 0.000137 | | System lock | 0.000076 | | optimizing | 0.000073 | | statistics | 0.000291 | | preparing | 0.000092 | | executing | 1.722548 | <<<<<<<<<<<<<<<<<< Efficiency dictates time, 1.7 seconds | end | 0.000050 | | query end | 0.046996 | | waiting for handler commit | 0.000072 | | closing tables | 0.000037 | | freeing items | 0.000170 | | cleaning up | 0.000067 | +--------------------------------+----------+ 18 rows in set (0.0008 sec) What the query SHOULD do ... ============================ -- Lookup the UNIQUE 'value' column in mdl_user_private_key -- Use the userid that is retrieved to JOIN on to id column in mdl_user via eq_ref (it's PK) -- That would result in potential 5 or 6 lookups total -- Query cost would likely be in milliseconds How to get there ... ==================== -- If you are brave, swap the order of the columns in index `mdl_userprivkey_scrval_ix` and make it a UNIQUE KEY, this would appear to be optimal solution, given the current data -- or, add a UNIQUE index on the 'value' column in mdl_user_private_key - but still need to understand if this will always be UNIQUE -- If not happy with that, just add a normal secondary index - ZERO potential downside to this except the for memory it will use -- Also possible to solve it by making the lookup on mdl_user_private_key a subquery, that would be inelegant and possibly wouldn't work well in versions of MySQL that -- don't support 'skip scan' (pre version 8) Simplest solution ================= ALTER TABLE `mdl_user_private_key` ADD KEY `uon_mdl_userprivkey_val_ix` (`value`); TESTING IN RC ============= -- Same plan picked in RC pre-change MySQL SQL > EXPLAIN SELECT u.id FROM mdl_user u JOIN mdl_user_private_key k ON u.id = k.userid WHERE u.deleted = 0 AND u.confirmed = 1 AND u.suspended = 0 AND k.value = 'c70d6d9e51ed81702bdfd73626ded013'; +----+-------------+-------+------------+-------------+-----------------------------------------+---------------------------------+---------+---------------+-------+----------+---------------------------------------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+-------------+-----------------------------------------+---------------------------------+---------+---------------+-------+----------+---------------------------------------------------------------+ | 1 | SIMPLE | u | NULL | index_merge | PRIMARY,mdl_user_del_ix,mdl_user_con_ix | mdl_user_del_ix,mdl_user_con_ix | 1,1 | NULL | 74932 | 10 | Using intersect(mdl_user_del_ix,mdl_user_con_ix); Using where | | 1 | SIMPLE | k | NULL | ref | mdl_userprivkey_use_ix | mdl_userprivkey_use_ix | 8 | rcmoodle.u.id | 1 | 10 | Using where | +----+-------------+-------+------------+-------------+-----------------------------------------+---------------------------------+---------+---------------+-------+----------+---------------------------------------------------------------+ 2 rows in set (0.0063 sec) MySQL SQL > SELECT u.id FROM mdl_user u JOIN mdl_user_private_key k ON u.id = k.userid WHERE u.deleted = 0 AND u.confirmed = 1 AND u.suspended = 0 AND k.value = 'c70d6d9e51ed81702bdfd73626ded013'; +--------+ | id | +--------+ | 242313 | +--------+ 1 row in set (1 min 49.2970 sec) <<<<<<<<<<<<<<<<< Clearly not in memory Test Change =========== MySQL SQL > ALTER TABLE `mdl_user_private_key` ADD KEY `mdl_userprivkey_val_ix` (`value`); Query OK, 0 rows affected (1.4564 sec) <<<<<<<<<<<<<<<< Smallish table and no load, will be a bit slower in live NEW EXPLAIN PLAN ================ MySQL SQL > EXPLAIN SELECT u.id FROM mdl_user u JOIN mdl_user_private_key k ON u.id = k.userid WHERE u.deleted = 0 AND u.confirmed = 1 AND u.suspended = 0 AND k.value = 'c70d6d9e51ed81702bdfd73626ded013'; +----+-------------+-------+------------+--------+-----------------------------------------------+------------------------+---------+-------------------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+--------+-----------------------------------------------+------------------------+---------+-------------------+------+----------+-------------+ | 1 | SIMPLE | k | NULL | ref | mdl_userprivkey_use_ix,mdl_userprivkey_val_ix | mdl_userprivkey_val_ix | 514 | const | 1 | 100 | NULL | | 1 | SIMPLE | u | NULL | eq_ref | PRIMARY,mdl_user_del_ix,mdl_user_con_ix | PRIMARY | 8 | rcmoodle.k.userid | 1 | 5 | Using where | +----+-------------+-------+------------+--------+-----------------------------------------------+------------------------+---------+-------------------+------+----------+-------------+ 2 rows in set (0.0010 sec) -- Note new index picked, single row estimate -- single row lookup in mdl_user -- order of tables use has been changed MySQL SQL > EXPLAIN ANALYZE SELECT u.id FROM mdl_user u JOIN mdl_user_private_key k ON u.id = k.userid WHERE u.deleted = 0 AND u.confirmed = 1 AND u.suspended = 0 AND k.value = 'c70d6d9e51ed81702bdfd73626ded013'\G *************************** 1. row *************************** EXPLAIN: -> Nested loop inner join (cost=0.70 rows=0) (actual time=0.069..0.073 rows=1 loops=1) -> Index lookup on k using mdl_userprivkey_val_ix (value='c70d6d9e51ed81702bdfd73626ded013') (cost=0.35 rows=1) (actual time=0.039..0.042 rows=1 loops=1) -> Filter: ((u.suspended = 0) and (u.confirmed = 1) and (u.deleted = 0)) (cost=0.26 rows=0) (actual time=0.027..0.027 rows=1 loops=1) -> Single-row index lookup on u using PRIMARY (id=k.userid) (cost=0.26 rows=1) (actual time=0.024..0.024 rows=1 loops=1) 1 row in set (0.0014 sec) RUNNING NEW VERSION =================== MySQL SQL > SELECT u.id FROM mdl_user u JOIN mdl_user_private_key k ON u.id = k.userid WHERE u.deleted = 0 AND u.confirmed = 1 AND u.suspended = 0 AND k.value = 'c70d6d9e51ed81702bdfd73626ded013'; +--------+ | id | +--------+ | 242313 | +--------+ 1 row in set (0.0123 sec) <<<<<<<<<<<<<<<<<<<<< one hundredth of a second MySQL SQL > show status like 'handler%'; +----------------------------+-------+ | Variable_name | Value | +----------------------------+-------+ | Handler_commit | 1 | | Handler_delete | 0 | | Handler_discover | 0 | | Handler_external_lock | 4 | | Handler_mrr_init | 0 | | Handler_prepare | 0 | | Handler_read_first | 0 | | Handler_read_key | 2 | <<<<<<<<<<<<<<<<< rows read | Handler_read_last | 0 | | Handler_read_next | 1 | <<<<<<<<<<<<<<<<< | Handler_read_prev | 0 | | Handler_read_rnd | 0 | | Handler_read_rnd_next | 0 | | Handler_rollback | 0 | | Handler_savepoint | 0 | | Handler_savepoint_rollback | 0 | | Handler_update | 0 | | Handler_write | 0 | +----------------------------+-------+ 18 rows in set (0.0028 sec) MySQL SQL > show profile for query 3; +--------------------------------+----------+ | Status | Duration | +--------------------------------+----------+ | starting | 0.000147 | | Executing hook on transaction | 0.000028 | | starting | 0.000025 | | checking permissions | 0.000021 | | checking permissions | 0.007890 | <<<<<<<<<< takes longer to check permissions than run the query | Opening tables | 0.000120 | | init | 0.000027 | | System lock | 0.000031 | | optimizing | 0.000048 | | statistics | 0.000295 | | preparing | 0.000058 | | executing | 0.000121 | <<<<<<<<<< query runtime | end | 0.000019 | | query end | 0.002969 | | waiting for handler commit | 0.000048 | | closing tables | 0.000035 | | freeing items | 0.000110 | | cleaning up | 0.000042 | +--------------------------------+----------+ 18 rows in set (0.0007 sec) Index would also help ===================== (In pre 8.0 MySQL) *************************** 6. row *************************** SCHEMA_NAME: ---- DIGEST: 942e5528d84e48fd36b4a347107b04f959ed50fb23947506af9705a4f2a65f2c DIGEST_TEXT: SELECT ? FROM `mdl_user_private_key` WHERE VALUE = ? LIMIT ?, ... COUNT_STAR: 8089 SUM_TIMER_WAIT: 27788967870000 MIN_TIMER_WAIT: 139022000 AVG_TIMER_WAIT: 3435402000 MAX_TIMER_WAIT: 489546171000 SUM_LOCK_TIME: 797004000000 SUM_ERRORS: 0 SUM_WARNINGS: 0 SUM_ROWS_AFFECTED: 0 SUM_ROWS_SENT: 0 SUM_ROWS_EXAMINED: 0 SUM_CREATED_TMP_DISK_TABLES: 0 SUM_CREATED_TMP_TABLES: 0 SUM_SELECT_FULL_JOIN: 0 SUM_SELECT_FULL_RANGE_JOIN: 0 SUM_SELECT_RANGE: 8089 SUM_SELECT_RANGE_CHECK: 0 SUM_SELECT_SCAN: 0 SUM_SORT_MERGE_PASSES: 0 SUM_SORT_RANGE: 0 SUM_SORT_ROWS: 0 SUM_SORT_SCAN: 0 SUM_NO_INDEX_USED: 0 SUM_NO_GOOD_INDEX_USED: 0 FIRST_SEEN: 2022-04-05 11:59:19.393773 LAST_SEEN: 2022-04-26 12:36:19.991389 QUANTILE_95: 12589254117 QUANTILE_99: 36307805477 QUANTILE_999: 173780082874 QUERY_SAMPLE_TEXT: SELECT 'x' FROM mdl_user_private_key WHERE value = '6f9afca18d5f828162cacfdd065ebbe2' LIMIT 0, 1 QUERY_SAMPLE_SEEN: 2022-04-26 12:36:19.991389 QUERY_SAMPLE_TIMER_WAIT: 371146000