【问题标题】:INNER JOIN with WHERE lower(...) like ... performanceINNER JOIN with WHERE lower(...) like ... 性能
【发布时间】:2018-03-28 16:03:12
【问题描述】:

我将查找所有作者姓名为“de%”的书籍不区分大小写

我写:

SELECT * FROM authors a
INNER JOIN books b ON books.author_id = a.id
WHERE lower(a.first_name) like 'de%'

这会导致书籍的 FULL TABLE ACCESS,基数为 2037700,成本为 4342。

和简单一模一样

SELECT * FROM books; -- Same 2037700 cardinality and 4342 cost

如何告诉 oracle 按作者 ID 过滤书籍?当然,我有 books.author_id 的索引。

我能达到的最接近的结果是:

SELECT /*+ index(b) */ * FROM books b WHERE author_id IN (SELECT id FROM authors a WHERE lower(a.first_name) like 'de%');
--gives 1028759 cardinality and 47282 cost - still not so good

更新

是的,我有两个关于 authors.first_name 的索引:

CREATE INDEX first_name_idx ON authors (first_name);
CREATE INDEX first_name_lower_idx ON authors (lower(first_name));

执行计划表明 使用了 first_name_lower_idx,但基数等于 FULL SCAN authors。

UPD2

是的,不使用小写字母表示性能要好得多。

UPD3

子字符串并没有让任何事情变得更好。

区分大小写

功能索引不区分大小写

不区分大小写,无索引

【问题讨论】:

  • 你有索引authors.first_name吗?
  • 这些天我不了解 Oracle,但较低的功能可能会导致索引被跳过。
  • 我怀疑优化器会首先过滤 a.first_name。并使用不区分大小写的排序规则而不是更低的排序规则。
  • 很好奇 WHERE substr(lower(a.first_name),0,2) = 'de' 是否会更好地使用索引。
  • 更高版本的 oracle 允许您创建基于函数的索引——类似于 create index i1 on books(lower(first_name));然后它将使用该索引。是的,否则如果您对列执行函数,它将不会使用索引。此外,如果您使用通配符开头,它将不会使用索引,所以像 'de%' 将使用索引但 '%de%' 不会

标签: sql oracle query-performance


【解决方案1】:

如果不使用索引,您的查询会好得多。此外,您似乎缺少连接。解释如下。

根据统计报告的基数,我假设Authors表有10431条记录,Books表有2037700条记录。

区分大小写的谓词WHERE cp.first_name like 'de%' 仅从Authors 表中获取10431 条记录中的13 条记录。随后与Books 表的连接仅从Books 表中获取2037700 条记录中的99 行。由于缺少一个或多个连接,您将获得 (13 * 99) 1257 行。尽管如此,这里还是倾向于使用索引,因为计数可以忽略不计。

不区分大小写的谓词WHERE lower(cp.first_name) like 'de%' 将“DE%”、“dE%”和“De%”名称也转换为“de%”名称。因此,在执行计划的第一步中,将从Authors 表中获取更多记录。根据执行计划的基数估计,不区分大小写的谓词从Authors 表中获取所有记录(10431 条记录)。随后与Book 表的连接过滤成1028912 条记录的最终结果集。如果您甚至使用提示强制在Books.author_id 上建立索引,您将命中所有(10431)author_ids 的索引。在这种情况下,索引只会是开销,而不是性能提升。

索引仅在以下情况下有用。

一个。当你取一张大桌子的一小部分时。 (索引唯一扫描或索引范围扫描) 湾。当查询中引用的所有列都是索引的一部分时。 (索引快速全扫描)。 C。当前导索引列具有低基数并且过滤器导致扫描最小数量的子树时。 (索引跳过扫描)。

另外请检查 Books.authors_id 是否有引用 Authors.id 的外键。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-28
    • 2019-01-15
    • 1970-01-01
    • 2021-11-29
    • 2015-01-09
    • 2012-05-28
    • 2012-06-01
    • 1970-01-01
    相关资源
    最近更新 更多