基于函数的索引没有提高查询性能
Posted
技术标签:
【中文标题】基于函数的索引没有提高查询性能【英文标题】:Function Based Index not improving query performance 【发布时间】:2020-01-03 15:01:41 【问题描述】:我已经创建了视图,在这个视图中我添加了下面我需要的 case 语句,并且我已经为它创建了基于函数的索引。该视图有 1900000 条记录。当我尝试执行视图时,它需要几个小时才能运行,并且该视图的性能非常低。我不明白如何提高性能。
CREATE OR REPLACE VIEW
TST_AGG
(
ROOT) AS
Select
CASE
WHEN regexp_like(ticker, '\s.*\s')
THEN SUBSTR(ticker, 1, instr(ticker, ' ')-1)
WHEN regexp_like(ticker, '\s')
THEN
CASE
WHEN regexp_like(SUBSTR(ticker, 1, instr(ticker, ' ')-1), '(P|C)$')
AND LENGTH(SUBSTR(ticker, 1, instr(ticker, ' ')-1)) >= 4
THEN SUBSTR(SUBSTR(ticker, 1, instr(ticker, ' ')-1), 1, LENGTH(SUBSTR(ticker, 1
, instr(ticker, ' ')-1))-3)
WHEN regexp_like(SUBSTR(ticker, 1, instr(ticker, ' ')-1), '\w\d\d\w\d$')
THEN SUBSTR(SUBSTR(ticker, 1, instr(ticker, ' ')-1), 1, LENGTH(SUBSTR(ticker, 1
, instr(ticker, ' ')-1))-5)
WHEN regexp_like(SUBSTR(ticker, 1, instr(ticker, ' ')), '\w\d\w\d$')
THEN SUBSTR(SUBSTR(ticker, 1, instr(ticker, ' ')-1), 1, LENGTH(SUBSTR(ticker, 1
, instr(ticker, ' ')-1))-4)
ELSE SUBSTR(ticker, 1, instr(ticker, ' ')-1)
END
WHEN regexp_like(ticker, '(P|C)$')
AND LENGTH(ticker) >= 4
THEN SUBSTR(ticker, 1, LENGTH(ticker)-3)
WHEN regexp_like(ticker, '\w\d\d\w\d$')
THEN SUBSTR(ticker, 1, LENGTH(ticker)-5)
WHEN regexp_like(ticker, '\w\d\w\d$')
THEN SUBSTR(ticker, 1, LENGTH(ticker)-4)
ELSE ticker
END ) AS ROOT
FROM TTT_IMP
以下是我创建的基于功能的索引:
CREATE INDEX "IDX_ROOT" ON "TTT_IMP" (CASE WHEN REGEXP_LIKE ("TICKER",'\s.*\s') THEN SUBSTR("TICKER",1,INSTR("TICKER",' ')-1) WHEN REGEXP_LIKE ("TICKER",'\s') THEN CASE WHEN ( REGEXP_LIKE (SUBSTR("TICKER",1,INSTR("TICKER",' ')-1),'(P|C)$') AND LENGTH(SUBSTR("TICKER",1,INSTR("TICKER",' ')-1))>=4) THEN SUBSTR(SUBSTR("TICKER",1,INSTR("TICKER",' ')-1),1,LENGTH(SUBSTR("TICKER",1,INSTR("TICKER",' ')-1))-3) WHEN REGEXP_LIKE (SUBSTR("TICKER",1,INSTR("TICKER",' ')-1),'\w\d\d\w\d$') THEN SUBSTR(SUBSTR("TICKER",1,INSTR("TICKER",' ')-1),1,LENGTH(SUBSTR("TICKER",1,INSTR("TICKER",' ')-1))-5) WHEN REGEXP_LIKE (SUBSTR("TICKER",1,INSTR("TICKER",' ')),'\w\d\w\d$') THEN SUBSTR(SUBSTR("TICKER",1,INSTR("TICKER",' ')-1),1,LENGTH(SUBSTR("TICKER",1,INSTR("TICKER",' ')-1))-4) ELSE SUBSTR("TICKER",1,INSTR("TICKER",' ')-1) END WHEN ( REGEXP_LIKE ("TICKER",'(P|C)$') AND LENGTH("TICKER")>=4) THEN SUBSTR("TICKER",1,LENGTH("TICKER")-3) WHEN REGEXP_LIKE ("TICKER",'\w\d\d\w\d$') THEN SUBSTR("TICKER",1,LENGTH("TICKER")-5) WHEN REGEXP_LIKE ("TICKER",'\w\d\w\d$') THEN SUBSTR("TICKER",1,LENGTH("TICKER")-4) ELSE "TICKER" END );
【问题讨论】:
对于使用索引的引擎,它需要与查询的过滤条件是 EXACT 匹配。是这样吗?您用于检索数据的查询是什么?你的问题没有显示出来。 精确匹配意味着它应该在哪里匹配?基于函数的索引的条件与视图案例语句的条件完全相同 请包含您用于检索数据的查询。那就是你想要快的,对吧? 您创建了TST_AGG
视图大概是为了在某处使用它从数据库中检索数据。从视图中看到的另一个SELECT
可能很慢。如果是这种情况,请在问题中包含该查询,因为这就是您想要的快速。
安德鲁,当你做'select * from tst_agg'时,它很慢吗?并且索引是在RRR_IMP而不是TTT_IMP,这两者有什么关系?
【参考方案1】:
索引可以在两种情况下使用。
1) 减少选中的记录,即
SELECT ... FROM TST_AGG where ROOT = ...
2) 避免查询表,并避免昂贵的计算
SELECT ROOT FROM TST_AGG
我在这里假设后者。如果优化器知道索引条目与表是一对一的,则它只能使用索引(代替表)。因为它不知道该表达式是否可能返回 NULL(未存储在索引中),所以除非您通知优化器,否则它无法进行直接交换。
因此
SELECT ROOT FROM TST_AGG
不会有机会使用索引,但是
SELECT ROOT FROM TST_AGG WHERE ROOT IS NOT NULL
应该可以。
要注意的另一件事是,我们可能会更改用于存储索引的表达式语法。所以检查 USER_IND_EXPRESSIONS,也许把那个表达式放回视图的定义中。
【讨论】:
所以你的意思是这里的优化器不承认我在 TST_AGG 中使用的 case 条件确实创建了任何基于函数的索引?如果是那么怎么做呢?因为这里的基于函数的索引并没有提高性能 将您的定义与 USER_IND_EXPRESSIONS 中存储的内容进行比较,然后调整您的定义以与其中的内容完全匹配。这通常不是问题,但它消除了它成为问题 现在我已经更新了问题并在我在 VIew 中使用它的同一张表上创建了索引...我不确定我创建的基于功能的索引和相同的条件我在 Select 子句中使用了视图,所以它有助于提高视图的性能,因为我在这个视图中有 100000 行,而我正在使用的 REGEX 条件试图从每一行中提取值? 基于函数的索引包含所有这些计算的结果。因此,使用它(用于完整扫描)应该避免评估的 CPU 成本【参考方案2】:我建议检查您的数据模型,正则表达式真的很难看。将相关信息直接存储在列中,而不是隐藏在 ticket
字符串中。
无论如何,我建议创建一个虚拟列而不是视图。然后你可以在这个虚拟列上创建一个索引,它也应该被使用。会是这样的:
ALTER TABLE TTT_IMP ADD (ROOT VARCHAR2(20) GENERATED ALWAYS AS (
CAST(
CASE
WHEN regexp_like(ticker, '\s.*\s')
THEN SUBSTR(ticker, 1, instr(ticker, ' ')-1)
WHEN regexp_like(ticker, '\s')
THEN
CASE
WHEN regexp_like(SUBSTR(ticker, 1, instr(ticker, ' ')-1), '(P|C)$')
AND LENGTH(SUBSTR(ticker, 1, instr(ticker, ' ')-1)) >= 4
THEN SUBSTR(SUBSTR(ticker, 1, instr(ticker, ' ')-1), 1, LENGTH(SUBSTR(ticker, 1
, instr(ticker, ' ')-1))-3)
WHEN regexp_like(SUBSTR(ticker, 1, instr(ticker, ' ')-1), '\w\d\d\w\d$')
THEN SUBSTR(SUBSTR(ticker, 1, instr(ticker, ' ')-1), 1, LENGTH(SUBSTR(ticker, 1
, instr(ticker, ' ')-1))-5)
WHEN regexp_like(SUBSTR(ticker, 1, instr(ticker, ' ')), '\w\d\w\d$')
THEN SUBSTR(SUBSTR(ticker, 1, instr(ticker, ' ')-1), 1, LENGTH(SUBSTR(ticker, 1
, instr(ticker, ' ')-1))-4)
ELSE SUBSTR(ticker, 1, instr(ticker, ' ')-1)
END
WHEN regexp_like(ticker, '(P|C)$')
AND LENGTH(ticker) >= 4
THEN SUBSTR(ticker, 1, LENGTH(ticker)-3)
WHEN regexp_like(ticker, '\w\d\d\w\d$')
THEN SUBSTR(ticker, 1, LENGTH(ticker)-5)
WHEN regexp_like(ticker, '\w\d\w\d$')
THEN SUBSTR(ticker, 1, LENGTH(ticker)-4)
ELSE ticker
END
AS VARCHAR2(20))
) VIRTUAL);
【讨论】:
现在我已经更新了问题并在我在 VIew 中使用它的同一张表上创建了索引...我不确定我创建的基于功能的索引和相同的条件我在 Select 子句中使用了视图,所以它有助于提高视图的性能,因为我在这个视图中有 100000 行,而我正在使用的 REGEX 条件试图从每一行中提取值? 不要创建基于函数的索引 - 创建一个虚拟列并为此列创建一个普通索引。在后台,Oracle 实际上会创建一个基于功能的索引。当您在 WHERE 子句中使用此列时,您可以确定使用了索引。 是的,我将创建虚拟列,但我只想知道我在表上创建的基于功能的索引,并且我在 select 子句中使用它来创建视图有助于提高视图性能或不是吗? 您仍然没有告诉我们“当我尝试执行视图时...”是什么意思,以及“有助于提高性能”是什么意思。在任何情况下,创建一个视图只需要几毫秒。当您选择没有任何 WHERE 子句的视图/表时,不使用索引(假设您只选择一个没有连接的表) 现在我明白了区别..在这个表中创建虚拟列之后还有一个问题,如果我试图插入说 1000000 行,它会影响行插入时间的性能,因为这个虚拟列会尝试在插入过程中为每一行执行一些条件?例如,目前在该表上插入 1000000 行需要 10 分钟,在该表上创建此虚拟列并尝试插入相同数量的行后,是否会影响插入性能?以上是关于基于函数的索引没有提高查询性能的主要内容,如果未能解决你的问题,请参考以下文章