[MDEV-9764] MariaDB does not limit memory used for range optimization Created: 2016-03-19 Updated: 2021-09-30 Resolved: 2017-01-15 |
|
| Status: | Closed |
| Project: | MariaDB Server |
| Component/s: | Optimizer |
| Affects Version/s: | 5.5, 10.0, 10.1, 10.2 |
| Fix Version/s: | 10.1.21, 10.2.4 |
| Type: | Bug | Priority: | Critical |
| Reporter: | Valerii Kravchuk | Assignee: | Sergei Golubchik |
| Resolution: | Fixed | Votes: | 2 |
| Labels: | upstream-fixed | ||
| Attachments: |
|
||||||||||||||||||||||||||||
| Issue Links: |
|
||||||||||||||||||||||||||||
| Sprint: | 10.2.1-1, 10.2.1-2, 5.5.50, 10.1.15, 10.2.4-1, 10.1.21 | ||||||||||||||||||||||||||||
| Description |
|
`Unlike MySQL 5.6 (that provides eq_range_index_dive_limit server variable) and MySQL 5.7 (that additionally provides range_optimizer_max_mem_size server variable) MariaDB 10.x does NOT limit memory used for range optimization in any way (neither directly nor indirectly). As a result, for some queries with huge list of value in the IN () list in the WHERE clause (having number of items comparable to the number of rows in the table) MariaDB 10.x does not only execute the query longer than MySQL 5.6 and 5.7 with default settings (as it spends more time on query optimization), but also uses a lot of memory in the process (see https://bugs.mysql.com/bug.php?id=78973 for some estimations and links). With many concurrent connections running this kind of queries we may easily end up with OOM condition for the mysqld process. Consider a table like this:
and a query like this:
Run the query on different versions of MySQL and MariaDB, compare execution times and memory used in the process. It may be easier to see the memory impact on versions that do not allow to monitor memory used per session or "state" by running many copies of the same query concurrently using mysqlslap, for example. |
| Comments |
| Comment by Valerii Kravchuk [ 2016-03-21 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
I've checked today with recent MariaDB 10.1.13 built from current sources on my QuadCore box. I've got the following results: Execution of the query:
Then I've executed mysqlslap like this:
and in another session got the following on memory usage:
Then mysqld process was killed by OOM killer:
With Percona Server 5.6.28-76.1 built from source on the same hardware I've got the following execution time:
and memory usage while the same mysqlsap was running the query in 100 connections based on top was like this:
The command completed successfully:
The system used for testing was like this:
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2016-04-30 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Some observations (these are not the direct cause of the problem but related). One reason for high memory consuption is:
MySQL-5.6 also has this big array. I didn't check other versions. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2016-04-30 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
opt_range.cc also has some other ways to prevent high memory usage:
these are not directly related to this bug | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2016-04-30 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
The patch that introduces @@eq_range_index_dive_limit is here: it replaces records_in_range() calls with use of index statistics (or some adjusted value?). This will remove [one cause of] the slowdown, but won't help with high memory consumption. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Valerii Kravchuk [ 2016-04-30 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
See http://bugs.mysql.com/bug.php?id=79450 also. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2016-05-01 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
The patch that limits memory consumption is here: It is done on a fairly low level, by limiting memory consumption of a MEM_ROOT pool (the capability to limit memory use of a MEM_ROOT is also used to limit the amount of memory used by the parser: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2016-05-10 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
A somewhat similar case: MDEV-10046 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2016-05-23 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Looking at mysql-5.7, found this: if one has a table with extended key
and a query that has equalities on a secondary index as well as PK:
Then it enumerates a combinatorial explosion of ranges:
but also it calls ha_innobase::records_in_range() for each of them. This goes against the idea of not calling records_in_range() for "equality ranges" (full key ranges on unique indexes). | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2016-05-25 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Looking at the testcase in the bug report again: == 10.1 ==
== mysql-5.7 == == mysql-5.7, no memory limit for range optimizer == Debugging, one can see that
== mysql-5.7, no eq_range_index_dive_limit == | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2016-05-31 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Pushed The patch doesn't put any limits on memory usage, but it makes memory usage much lower. == 10.1-patch1 == information_schema.processlist.memory_used: 26,091,264 (was: 67,746,520) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2016-05-31 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Note that the above is still higher than the HIGH_NUMBER_OF_BYTES_USED: 10,241,280 number we've got for mysql-5.7, no eq_range_index_dive_limit above. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2016-05-31 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MariaDB uses more memory because it allocates more SEL_TREE objects.
This causes MariaDB to allocate 2x more SEL_TREE objects than the number of elements in (c1,c2, ... cN) list. For the example, I see 88213 SEL_TREEs allocated. MySQL 5.7 with range_optimizer_max_mem_size=1024*1024*1024 setting allocates only 44108 SEL_TREE objects. Looking why MariaDB doesn't reuse... it comes from this patch:
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2016-05-31 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
If we made tree_or not to allocate a SEL_TREE in this case, we would gain (sizeof(SEL_TREE)=120) * 44108=5,292,960 bytes. get_mm_tree currently uses 16,605,264 bytes so it would one third. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2016-06-01 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Conclusions from yesterday scrum discussion: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2016-06-02 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Pushed patch2, 7d3d75895d9d29d52c34dd3559cec59731d8d267. == 10.1-patch2 == The amount of memory used by the range optimizer is now roughly the same what 5.7 would use (see HIGH_NUMBER_OF_BYTES_USED: 10,241,280 above) when one sets the settings to make it apples-to-apples comparison). | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2016-06-03 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Pushed a fix for | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Golubchik [ 2016-10-10 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Still no hard limit on memory used, so still possible to trigger OOM. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2016-12-08 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Without the cap.. we have test_quick_select code use about 10M memory for a 300K query. That is, about 30x the size of the query. You can get the multiplier to be bigger if there are multiple potential indexes. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2016-12-08 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Debugging the query explain-mdev9764-12.sql (query text takes 39K)
The IN list has 5480 elements. I can see 5481 SEL_TREE objects alloced. sizeof(SEL_TREE)=120. This is responsible for 120*5480 = 657,600 = 657K of mem usage Each SEL_TREE object has
619+658=~1.2M, which agrees with the data on the chart. Conclusions:
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Valerii Kravchuk [ 2016-12-08 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Queries of this kind, with long IN () lists, are usually dynamically generated by software that may be out of DBA's control. Here hard limits (using any of the way implemented in upstream MySQL (eq_range_index_dive_limit and/or range_optimizer_max_mem_size) help DBA to keep server more safe. Also, what about that part of the original report related to time spent on optimization (for no real gain, when number of items in the IN list is approaching number of rows in the table)? Hard limits solve this problem as well. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2016-12-10 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Ok, finally it became clear that A) other linked MDEV issues are different from this one, and B) although some solutions are possible for this particular issue (will file an MDEV), all of them will be too intrusive to be put into a 10.1 release. So, thinking of backporting the @@range_optimizer_max_mem_size fix from MySQL. The patch in MySQL is: Possible concerns when applying this on MariaDB 10.1:
The wording is not entirely correct, because range optimization may be still done for other tables. Do we want the warning to be printed at all?
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Golubchik [ 2017-01-15 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Added a new server option/variable --max-session-mem-used that implements a | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Simone [ 2018-02-21 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Is it possible for this bug to affect version 10.0.30? I'm having some random OOM issues, and I've seend queries with megabytes (literaly) of "IN"/"NOT IN" clause. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Golubchik [ 2018-08-15 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Yes, it affects all versions below what is listed in FixVersion/s field. So, all 5.5 and 10.0 versions. |