INNER JOIN与WHERE lower(...)类似......表现

时间:2018-03-28 16:03:13

标签: sql oracle query-performance

我将找到所有作者的名字,例如' de%'的不区分大小写的

我写道:

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

这导致书籍的全表访问,基数为2037700,成本为4342.

与简单

完全相同
SELECT * FROM books; -- Same 2037700 cardinality and 4342 cost

如何告诉oracle按照作者身份过滤书籍?当然,我有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

UPD

是的,我有两个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作者。

UPD2

是的,no-lowercase表现出更高的性能。

UPD3

子串并没有做得更好。

区分大小写 case sensitive

对功能索引不敏感 case insensitive with functional index

不带索引的不区分大小写 case insensitive without index

1 个答案:

答案 0 :(得分:0)

如果不使用索引,您的查询会好得多。你似乎也错过了联接。以下说明。

根据统计报告的基数,我假设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%' \ n”' dE%'和' De%'名字也分为' de%'名。因此,在执行计划的第一步中将从Authors表中获取更多记录。根据执行计划的基数估计,不区分大小写的谓词从Authors表中获取所有记录(10431条记录)。随后将Book表过滤器连接到1028912条记录的最终结果集中。如果您甚至使用提示强制Books.author_id上的索引,您将点击所有(10431)author_ids的索引。在这种情况下,索引只是开销,而不是性能改进。

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

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

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