[MDEV-29129] Performance regression starting in 10.6: unlimited "select order by limit" always using temporary, taking between 60x and 2000x longer in 10.6, 10.7, and 10.8 than in 10.5 Created: 2022-07-19 Updated: 2023-05-19 Resolved: 2022-12-03 |
|
| Status: | Closed |
| Project: | MariaDB Server |
| Component/s: | Optimizer |
| Affects Version/s: | 10.6.8, 10.7.4, 10.8.3 |
| Fix Version/s: | 10.11.2, 10.6.12, 10.7.8, 10.8.7, 10.9.5, 10.10.3 |
| Type: | Bug | Priority: | Critical |
| Reporter: | Juan | Assignee: | Sergei Petrunia |
| Resolution: | Fixed | Votes: | 4 |
| Labels: | regression, regression-10.6, regression-10.7, regression-10.8 | ||
| Environment: |
Rocky 8.6 |
||
| Attachments: |
|
||||||||||||
| Issue Links: |
|
||||||||||||
| Description |
|
Attached file reproduces: a simple select using no where clause but using limit, with order-by on an unindexed attribute, against a table with a little over 500,000 rows, takes about 0.150s in 10.5.15, while in 10.6.8, 10.7.4, and 10.8.3 the same query consistently takes about 10s. When an index is added, the difference is much more dramatic. 10.5 drops from 0.150s to 0.004s, while 10.6, 10.7, and 10.8 all remain unchanged at 10s. The explain plan shows that 10.6-10.8 always create a temporary table in addition to using filesort (or an index), while 10.5 just uses filesort in the first case and index in the second w/o needing to create a temporary table in either case. Increasing sort_buffer_size up to 512M makes no difference. One significant change is that the metadata (system) character set in 10.5 is utf8, whereas starting with 10.6 it's utf8mb3.
Unindexed 10.5 explain:
Unindexed 10.6, 10.7, 10.8 explain
Typical indexed 10.5 performance
Typical unindexed 10.5 performance
Typical indexed 10.6 through 10.8 performance
Typical unindexed 10.6 through 10.8 performance
|
| Comments |
| Comment by Sergei Petrunia [ 2022-09-14 ] | |||||||||||||||||
|
Ok, the query is using a stored routine call:
I added
into the TEST_RETURN_LOOKUP_VALUE function code. On 10.9, after running the query, I get this:
... while on 10.5, I get this:
| |||||||||||||||||
| Comment by Oleg Smirnov [ 2022-09-14 ] | |||||||||||||||||
|
The change was introduced with The workaround for this issue is to declare the function as DETERMINISTIC:
We are currently not sure if it's a bug or not, will discuss it with the team. | |||||||||||||||||
| Comment by Sergei Petrunia [ 2022-09-15 ] | |||||||||||||||||
|
Takeaways from the discussion at the SQL Processor Call: It looks like Stored Routines that are not declared as DETERMINISTIC have properties similar to RAND(). The optimizer has very little freedom in optimizing how to invoke them, they should be computed for every row combination that's checked. If this is so, the observed behavior is expected. If one wants the optimizer to be able to reduce the number of times the function is evaluated they should either declare the routine as DETERMINISTIC, or rewrite the query so that the stored function is invoked after the LIMIT is applied:
| |||||||||||||||||
| Comment by Oleg Smirnov [ 2022-09-28 ] | |||||||||||||||||
|
Closing this as not a bug since the customer is satisfied with the suggested solution. | |||||||||||||||||
| Comment by Sergei Petrunia [ 2022-11-29 ] | |||||||||||||||||
|
Current code has two algorithms for ORDER BY: 1. Sort the first table. When sorting the temporary table, the values of select list are computed when writing into the temporary table (This is the cause of the issues observed here) Monty's patch added this: Simple solution (#1)Adjust Monty's patch: Set JOIN::rand_table_in_field_list only if the select list has Simple solution (#2)Should a stored function call have RAND_TABLE_BIT? Alternative solution (#3)If the select list has EXPENSIVE_FUNC(t1.col1, t2.col2, ...) Note that references to (t1.col1, t2.col2, ...) in EXPENSIVE_FUNC(t1.col1, t2.col2, ...) should be replaced with references to temp.table fields. This all is implemented for GROUP BY already, consider
We just need to enable it here. This is however much more risky than solution #1 or #2. | |||||||||||||||||
| Comment by Sergei Petrunia [ 2022-11-29 ] | |||||||||||||||||
|
It's easy implement solution #1: https://github.com/MariaDB/server/tree/bb-10.6-mdev29129 ... (EDIT: wait it might be incorrect) | |||||||||||||||||
| Comment by Sergei Petrunia [ 2022-12-03 ] | |||||||||||||||||
|
Fix pushed into 10.6. |