我可以要求 Firebird 在其他列的左连接条件中使用索引(在字符串上使用 like )吗?
Can I ask Firebird to use index (with like on strings) in left join condition on other column?
我有table个结构:
journal_entries (id integer, account varchar(20), doc_date, date, amount numeric(15,4))
selected_accounts (account varchar(20), selection_id integer)
我可以查询这个并且 SQL 在 doc_date 和帐户上使用了索引:
select je.*
from journal_entries je
where je.doc_date>='01.01.2022' and
je.doc_date<='31.03.2022' and
(je.account like '23%' or
je.account like '24%')
但是当我用数据填充 selected_accounts table 时:
23%, 1
24%, 1
我正在尝试在左连接中使用条件:
select
from selected_accounts sa
left join journal_entries je on (
je.doc_date>='01.01.2022' and
je.doc_date<='31.03.2022' and
je.account like sa.account)
然后 SQL 没有在 journal_entries.account 数据上使用索引,它只在 je.doc_date 上使用索引。
我可以给优化器或 SQL 引擎一些提示,条件 je.account like sa.account
应该在 je.account
上使用索引吗?
我正在使用 Firebird 3.1 和 Firebird 2.1,但我想这个问题也出现在其他 SQL 数据库上。
我倾向于接受我无法使用左连接条件进行最佳查询的事实...
问题补充: 我将第一个查询的计划(例如 IBExpert 给出的)作为 plan
子句复制到第二个查询,但是 SQL 引擎报告:
index <index on journal_entries.account> cannot be used in the specified plan
所以,我的查询中有些东西阻止了对 journal_entries.account
索引的引用和使用。
额外观察: 事实上 - 我的数据库在 2022 年第一季度(我的示例中指定的时间段)有 1M 的日记条目,然后第一个(好的)查询报告少于 1M 的索引记录读取,但第二个(错误的)查询报告 2*1M 索引记录读取(索引是因为 journal_entries.doc_date
上的索引),因此,这比 doc_date
的完整读取更糟糕,然后只是过滤通过 selected_records
个条目。
向前迈进了一步: 感谢@Damien_The_Unbeliever 评论我做了这个测试(原文如此!第一个字符串以 % 为前缀):
select je.*
from journal_entries je
where je.doc_date>='01.01.2022' and
je.doc_date<='31.03.2022' and
(je.account like '%23%' or
je.account like '24%')
并且不再使用 je.account
索引并且读取次数增加了。所以 - 在我看来,Firebird 查询 engine/optimizer 扫描在 like
条件下使用的字符串文字,并决定在 je.account
.
上使用索引的可能性
所以,也许我可以通知 Firebird(对于我的 second/slow 查询)我只希望 post-%-fixed 字符串为 select_accounts.account output
?对于 Firebird 引擎,这将解决我的问题。
在这种情况下无法优化 like
,因为 Firebird 无法知道您的列有哪些值。 somecolumn like '24%'
可以使用索引的事实是因为 Firebird 会将 重写 该表达式为 somecolumn starting with '24'
(另请参阅 LIKE
,特别是标题为 “关于 LIKE
和优化器”)。使用从列中获取的参数或值是不可能的。
换句话说,解决您的问题的明显方法是让 selected_accounts.account
不是 '24%'
,而是 '24'
,并在您的 STARTING WITH
中使用 STARTING WITH
加入条件。
在通配符并不总是出现的情况下,有时您需要精确匹配,您可以使用 je.account starting with replace(sa.account, '%', '') and je.account like sa.account
之类的东西。此解决方案假定 %
仅作为最后一个字符出现,并且未使用 _
通配符。
我有table个结构:
journal_entries (id integer, account varchar(20), doc_date, date, amount numeric(15,4))
selected_accounts (account varchar(20), selection_id integer)
我可以查询这个并且 SQL 在 doc_date 和帐户上使用了索引:
select je.*
from journal_entries je
where je.doc_date>='01.01.2022' and
je.doc_date<='31.03.2022' and
(je.account like '23%' or
je.account like '24%')
但是当我用数据填充 selected_accounts table 时:
23%, 1
24%, 1
我正在尝试在左连接中使用条件:
select
from selected_accounts sa
left join journal_entries je on (
je.doc_date>='01.01.2022' and
je.doc_date<='31.03.2022' and
je.account like sa.account)
然后 SQL 没有在 journal_entries.account 数据上使用索引,它只在 je.doc_date 上使用索引。
我可以给优化器或 SQL 引擎一些提示,条件 je.account like sa.account
应该在 je.account
上使用索引吗?
我正在使用 Firebird 3.1 和 Firebird 2.1,但我想这个问题也出现在其他 SQL 数据库上。
我倾向于接受我无法使用左连接条件进行最佳查询的事实...
问题补充: 我将第一个查询的计划(例如 IBExpert 给出的)作为 plan
子句复制到第二个查询,但是 SQL 引擎报告:
index <index on journal_entries.account> cannot be used in the specified plan
所以,我的查询中有些东西阻止了对 journal_entries.account
索引的引用和使用。
额外观察: 事实上 - 我的数据库在 2022 年第一季度(我的示例中指定的时间段)有 1M 的日记条目,然后第一个(好的)查询报告少于 1M 的索引记录读取,但第二个(错误的)查询报告 2*1M 索引记录读取(索引是因为 journal_entries.doc_date
上的索引),因此,这比 doc_date
的完整读取更糟糕,然后只是过滤通过 selected_records
个条目。
向前迈进了一步: 感谢@Damien_The_Unbeliever 评论我做了这个测试(原文如此!第一个字符串以 % 为前缀):
select je.*
from journal_entries je
where je.doc_date>='01.01.2022' and
je.doc_date<='31.03.2022' and
(je.account like '%23%' or
je.account like '24%')
并且不再使用 je.account
索引并且读取次数增加了。所以 - 在我看来,Firebird 查询 engine/optimizer 扫描在 like
条件下使用的字符串文字,并决定在 je.account
.
所以,也许我可以通知 Firebird(对于我的 second/slow 查询)我只希望 post-%-fixed 字符串为 select_accounts.account output
?对于 Firebird 引擎,这将解决我的问题。
在这种情况下无法优化 like
,因为 Firebird 无法知道您的列有哪些值。 somecolumn like '24%'
可以使用索引的事实是因为 Firebird 会将 重写 该表达式为 somecolumn starting with '24'
(另请参阅 LIKE
,特别是标题为 “关于 LIKE
和优化器”)。使用从列中获取的参数或值是不可能的。
换句话说,解决您的问题的明显方法是让 selected_accounts.account
不是 '24%'
,而是 '24'
,并在您的 STARTING WITH
中使用 STARTING WITH
加入条件。
在通配符并不总是出现的情况下,有时您需要精确匹配,您可以使用 je.account starting with replace(sa.account, '%', '') and je.account like sa.account
之类的东西。此解决方案假定 %
仅作为最后一个字符出现,并且未使用 _
通配符。