patternsqlMinor
Testing MySQL adaptive_hash_index option
Viewed 0 times
optionmysqltestingadaptive_hash_index
Problem
We recently migrated our application to an entirely new infrastructure, going from a single server managing everything to a kubernetes cluster and dedicated database server running on AWS RDS. On Thursday, we had a planned spike in traffic due to marketing campaigns being sent, and during the middle of this peak we experienced a huge slow down in response times. Upon initial investigations, we discovered it was because the database was running at 100% CPU usage, and all queries were taking a long time to return (expected given the CPU usage)
We've never seen this behaviour before, so we're trying to determine if we've simply hit the max capacity of the server for that workload, or if we can improve this. During our research, we came across a few posts discussing the
The posts we saw suggested that in some applications, it may be beneficial to disable the
We don't usually have the level of traffic we saw, and under our usual workload we have absolutely no performance issue that we're aware of. The queries that were taking a long time to respond at peak, don't usually take more than
This query took just under 2 minutes to return 10,541 rows. Running this query now when the system isn't under load, it takes ~250ms. Below is the explain plan
```
+-------------+---------+------------+--------+------------
We've never seen this behaviour before, so we're trying to determine if we've simply hit the max capacity of the server for that workload, or if we can improve this. During our research, we came across a few posts discussing the
adaptive_hash_index option. We came across this because when we analysed the data from RDS, we saw a lot of btr_search waits.The posts we saw suggested that in some applications, it may be beneficial to disable the
adaptive_hash_index option. What we need to know though, is would this be beneficial given what we're seeing here, and more importantly how can we test that it has actually done anything and made a positive difference?We don't usually have the level of traffic we saw, and under our usual workload we have absolutely no performance issue that we're aware of. The queries that were taking a long time to respond at peak, don't usually take more than
SELECT
table_a.id
, table_a.name
FROM table_a
INNER JOIN table_b ON table_a.id = table_b.product_id
INNER JOIN table_c ON table_b.brochure_id = table_c.id
WHERE table_c.id = 215
AND table_a.enabled = TRUE
AND table_a.table_d_id = 20
AND table_a.ref IS NULL
ORDER BY table_a.name;
This query took just under 2 minutes to return 10,541 rows. Running this query now when the system isn't under load, it takes ~250ms. Below is the explain plan
```
+-------------+---------+------------+--------+------------
Solution
The first query might start with table_a or it might start with table_c. Here are the indexes to facilitate both query plans, thereby letting the Optimizer pick which seems better based on the data:
Since the only references to table_c are
you may as well replace them with just
Is table_b a many-to-many mapping table. It is common for them to be inefficiently indexed. See my guidelines: http://mysql.rjweb.org/doc.php/index_cookbook_mysql#many_to_many_mapping_table
For the Second query, here are some things to get started with (in addition to the many:many advice, above):
EXPLAINs
Here is a partial attempt at explaining the
table_a: -- I assume you have `PRIMARY KEY(id)`?
table_a: INDEX(enabled, table_d_id, ref, -- in any order, then
name) -- last
table_b: INDEX(product_id, brochure_id) -- see link below
table_b: INDEX(brochure_id, product_id)
table_c: -- I assume you have `PRIMARY KEY(id)`?Since the only references to table_c are
INNER JOIN `table_c` ON `table_b`.`brochure_id` = `table_c`.`id`
WHERE `table_c`.`id` = 215you may as well replace them with just
WHERE `table_b`.`brochure_id` = 215Is table_b a many-to-many mapping table. It is common for them to be inefficiently indexed. See my guidelines: http://mysql.rjweb.org/doc.php/index_cookbook_mysql#many_to_many_mapping_table
For the Second query, here are some things to get started with (in addition to the many:many advice, above):
a: INDEX(enabled, published, -- in either order, then
table_f_id) -- lastEXPLAINs
Here is a partial attempt at explaining the
EXPLAINs that you have:Using temporary; Using filesort- At one (or possibly more) step of the execution something needs to be sorted, usually because ofORDER BY.GROUP BY x ORDER BY wmay lead to multiple sorts;EXPLAINdoes not indicate that, butEXPLAIN FORMAT=JSONdoes. "Filesort" does not necessarily indicate that the disk is involved.
Using index- The index was a "covering index", meaning that all the columns used anywhere in the query were found in a singleINDEX. This is usually beneficial for performance but is rarely a goal to start with.
key_len = 4- probably a 4-byteINT NOT NULL(signed or unsigned);=5probably meansINT NULL. Consider making itNOT NULL. (This is a minor issue.)
- The
Rowscolumn - Multiply the numbers in that column together to get a very crude estimate of work to perform the query. This is sometimes useful in comparing two Explains.
Rows=1- May indicate a unique key, hence a very efficientJOIN.
Rows = big number- The table may have a lousy index.
JOINsare usually done via "NLJ" (Nested Loop Join) - read one table, reaching into the next table one row at a time.
- The first row - The
tablein the first row is likely to be the one with the bestWHEREs. If not, perhaps you need a better index -- often a composite index.
Code Snippets
table_a: -- I assume you have `PRIMARY KEY(id)`?
table_a: INDEX(enabled, table_d_id, ref, -- in any order, then
name) -- last
table_b: INDEX(product_id, brochure_id) -- see link below
table_b: INDEX(brochure_id, product_id)
table_c: -- I assume you have `PRIMARY KEY(id)`?INNER JOIN `table_c` ON `table_b`.`brochure_id` = `table_c`.`id`
WHERE `table_c`.`id` = 215WHERE `table_b`.`brochure_id` = 215a: INDEX(enabled, published, -- in either order, then
table_f_id) -- lastContext
StackExchange Database Administrators Q#279751, answer score: 3
Revisions (0)
No revisions yet.