我可以要求 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 之类的东西。此解决方案假定 % 仅作为最后一个字符出现,并且未使用 _ 通配符。