Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Partial index using ranges not been selected in plan #8349

Open
todaysoftware opened this issue Dec 10, 2024 · 3 comments
Open

Partial index using ranges not been selected in plan #8349

todaysoftware opened this issue Dec 10, 2024 · 3 comments

Comments

@todaysoftware
Copy link

In Firebird 5.0.1 when using a partial index with various range selections it always seems to fall back to a table scan (PLAN NATURAL)

CREATE INDEX AUDIT_LINETYPE ON AUDIT(LINETYPE) WHERE LINETYPE > 0 AND LINETYPE < 32767;

SELECT * FROM AUDIT WHERE LINETYPE = 42;
Select Expression
    -> Filter
        -> Table "AUDIT" Full Scan
(i.e. PLAN (AUDIT NATURAL))

Tried various other options such as LINETYPE > 0, LINETYPE IN (40,41,42,43,44,45,46,47), LINETYPE BETWEEN 40 AND 47, all of which result in a table scan, But the following does work (and technically is probably equivalent to the IN ( ) above)
LINETYPE = 40 OR LINETYPE = 41 OR LINETYPE = 42 OR ... OR LINETYPE = 47

SELECT TranNo FROM Audit  WHERE  LINETYPE = 42;
Select Expression
    -> Filter
        -> Table "AUDIT" Access By ID
            -> Bitmap
                -> Index "AUDIT_LINETYPE" Range Scan (full match)

But is is pretty inconvenient since there is probably a couple of dozen line types that should be included in the partial index so using a range or IN would be much better. The condition mentioned at the top would be OK since in our case around 3/4 of the values in the index would be either 0 or 32767, but probably ideally something like the following would be slightly better to exclude some additional values we are not interested in.

(LINETYPE BETWEEN 1 AND 7999) OR (LINETYPE BETWEEN 8100 AND 32766)

(possibly related to #7804 )

@todaysoftware todaysoftware changed the title Partial index not been selected in plan with ranges Partial index using ranges not been selected in plan Dec 10, 2024
@dyemanov
Copy link
Member

The optimizer cannot detect that value 42 matches the index range, as expressions are not evaluated at compile time. You need to specify that explicitly:

SELECT * FROM AUDIT WHERE LINETYPE > 0 AND LINETYPE < 32767 AND LINETYPE = 42;

This may look cumbersome but should work.

@todaysoftware
Copy link
Author

todaysoftware commented Dec 11, 2024

Thanks for the reply 👍. I have modified the filter on the index to use OR instead (a couple of dozen conditions covers most of our use cases fine). After doing this we get the following results

SHOW INDEX AUDIT_LINETYPE;
AUDIT_LINETYPE INDEX ON AUDIT(LINETYPE)
 WHERE LINETYPE=2 OR LINETYPE=4 OR ... LINETYPE=40 OR LINETYPE=41 OR LINETYPE=42 OR LINETYPE=43 OR ... LINETYPE=50

SELECT * FROM AUDIT WHERE LINETYPE = 42;
Select Expression
    -> Filter
        -> Table "AUDIT" Access By ID
            -> Bitmap
                -> Index "AUDIT_LINETYPE" Range Scan (full match)

SELECT * FROM AUDIT WHERE LINETYPE IN (43);
Select Expression
    -> Filter
        -> Table "AUDIT" Access By ID
            -> Bitmap
                -> Index "AUDIT_LINETYPE" Range Scan (full match)

SELECT * FROM AUDIT WHERE LINETYPE IN (42,43);
Select Expression
    -> Filter
        -> Table "AUDIT" Full Scan

SELECT * FROM AUDIT WHERE (LINETYPE = 42 OR LINETYPE = 43);
Select Expression
    -> Filter
        -> Table "AUDIT" Access By ID
            -> Bitmap Or
                -> Bitmap
                    -> Index "AUDIT_LINETYPE" Range Scan (full match)
                -> Bitmap
                    -> Index "AUDIT_LINETYPE" Range Scan (full match)

So the outlier there is the IN (42,43) however changing that to an OR works. I do feel that they should get the same result (i.e. both use the index) so maybe something to look at. I had a feeling a read somewhere that the parser/optimizer actually turns IN( ) into OR anyway so they should end up being equivalent. (but this inconsistency is something we can deal with although having it work consistently sometime in the future would be nice)

@dyemanov
Copy link
Member

Starting with v5, IN is not decomposed into ORs but instead is processed natively.
That said, partial index matching could be improved to handle your case (it was already noted in #7804).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants