[MDEV-6384] It seems like OPTIMIZER take into account the order of indexes in the table. Created: 2014-06-25 Updated: 2014-10-11 Resolved: 2014-09-09 |
|
| Status: | Closed |
| Project: | MariaDB Server |
| Component/s: | None |
| Affects Version/s: | 5.5.39, 10.0.11 |
| Fix Version/s: | 10.1.1 |
| Type: | Bug | Priority: | Critical |
| Reporter: | Seunguck Lee | Assignee: | Sergei Petrunia |
| Resolution: | Fixed | Votes: | 0 |
| Labels: | optimizer, order-by-optimization | ||
| Environment: |
Linux matt001 2.6.18-308.el5 #1 SMP Tue Feb 21 20:06:06 EST 2012 x86_64 x86_64 x86_64 GNU/Linux |
||
| Attachments: |
|
||||||||||||
| Issue Links: |
|
||||||||||||
| Description |
|
I created two test table. The only difference between them is the order of secondary index. Here's the problem.
How can I make optimizer use ix_fd1_fdpk to avoid filesort operation (Without index hint ^^) ?
==> The last query doesn't need filesort operation when they use ix_fd1_fdpk index. But not.. |
| Comments |
| Comment by Sergei Petrunia [ 2014-07-02 ] | ||||||||||||||||||||||||||
|
The report doesn't specify the dataset (types of columns not known, and the query that fills the tables uses information_schema.columns whose contents are different on every database). Matt74, if you still have tb_test1 and tb_test2 tables, could you please attach a mysqldump of these to make sure we're looking at the same problem? | ||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2014-07-02 ] | ||||||||||||||||||||||||||
|
I've created a test dataset that I believe (but not 100% certain) to be similar. Attaching mdev6384-psergey-try1.sql. | ||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2014-07-02 ] | ||||||||||||||||||||||||||
|
And the problem I'm observing is as follows. two tables, t1 and t2, are identical except the order of indexes:
Now, if we run the same query on t1 and t2, we will see different query plans:
Both plans scan the same range of values. the plan with "Using filesort" is apparently more expensive. Why is it picked. Why does optimizer's choice between /different/ query plans depend on the order of indexes in the table? I'll investigate this. | ||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2014-07-02 ] | ||||||||||||||||||||||||||
|
Debugging
one can see that the range optimizer choses ref(ix_fd1_fdpk), later test_if_skip_sort_order() finds that using this index produces the required ordering. Everything looks ok. Debugging
one can see that
OK
Now, we think that with index `ix_fd1_fdpk` we will read more rows than with `ix_fd1_fd2`. This is wrong. Eventually we arrive at this estimate
while the original estimate was
This is apparently wrong. I am not sure which part of test_if_cheaper_ordering() is wrong, I'll investigate further. | ||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2014-07-02 ] | ||||||||||||||||||||||||||
|
The source of read_time=22 is best_access_path: tmp=table->quick_rows[key]=192
rows + ranges = 21 + 1 = 22. | ||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2014-07-03 ] | ||||||||||||||||||||||||||
|
Debugging further, I find two problems.
we have refkey_rows_estimate=192 if we assume that condition on the index being tested (ix_fd1_fdpk) is not correlated with ref_key (ix_fd1_fd2), then
"Every 10th record matches the where clause". In order to get select_limit matching records, we'll need to read select_limit / selectivity= 10000 rows. The table has only table_records=1640 rows, so we set select_limit=1640. So, we don't take correlation into account and that causes us to have the wrong LIMIT value. I've tried setting the right LIMIT value in debugger, and it still picks the wrong plan. | ||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2014-07-03 ] | ||||||||||||||||||||||||||
|
The second problem part is here:
This is where we get index_scan_time=1640 (or 1000 if I force select_limit=1000 like in previous comment). This totally ignores the fact that the index in question has a potential range access with much lower #rows and cost. | ||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2014-07-03 ] | ||||||||||||||||||||||||||
|
So, if we set select select_limit = table->quick_rows[nr] = 192 right before the line quoted above.. that still doesn't help, we get
| ||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2014-07-03 ] | ||||||||||||||||||||||||||
|
Let's compare cost numbers from different parts of the optimizer: == range optimizer == == ref optimizer (best_access_path() function) == == ORDER BY optimizer == == Conclusions == | ||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2014-07-03 ] | ||||||||||||||||||||||||||
|
Unification of cost model across the optimizer is definitely outside of the scope of this bugfix. As an interim solution:
| ||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2014-07-07 ] | ||||||||||||||||||||||||||
|
There are issues with the above approach. If we solve it the simple way, we will need to allocate arrays to store potential ref(const) costs for each index in each used table We could do some pre-processing to make the set of potentially usable indexes smaller. That would require touching a lot of optimizer code. How about considering an alternative: re-caculate the costs in test_if_cheaper_ordering(), as requested. | ||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2014-07-07 ] | ||||||||||||||||||||||||||
|
In order to re-calculate the costs, we need to tell whether we're caclulating table->quick_rows/quick_costs can provide range access costs and #rows. Note that potential range access over one interval is not the same as
this is a 1-interval range access but ref(const) is not considered for this Q: Could we reuse best_access_path()? | ||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2014-07-08 ] | ||||||||||||||||||||||||||
|
Committed a patch: http://lists.askmonty.org/pipermail/commits/2014-July/006282.html | ||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2014-07-10 ] | ||||||||||||||||||||||||||
|
The patch is going through the QA. | ||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2014-08-27 ] | ||||||||||||||||||||||||||
|
See updates at One problem with this fix is that it is getting too big for 10.0. It is ok to include in 10.1, but pushing this change into 10.0 may cause an unwanted regression for somebody. |