【发布时间】: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