sql - 使用函数来轻松编写 SQL 真的很慢
问题描述
create or replace FUNCTION FUNCTION_X
(
N_STRING IN VARCHAR2
) RETURN VARCHAR2 AS
BEGIN
RETURN UPPER(translate(N_STRING, 'ÁÇÉÍÓÚÀÈÌÒÙÂÊÎÔÛÃÕËÜáçéíóúàèìòùâêîôûãõëü','ACEIOUAEIOUAEIOUAOEUaceiouaeiouaeiouaoeu'));
END FUNCTION_X;
SELECT 大约需要 5 秒(80k + 行)
SELECT TABLE_A.STRING_X
FROM TABLE_A
INNER JOIN TABLE_B ON TABLE_B.ID = TABLE_A.IDTB
WHERE
UPPER(UPPER(translate(TABLEB.STRING_X,
'ÁÇÉÍÓÚÀÈÌÒÙÂÊÎÔÛÃÕËÜáçéíóúàèìòùâêîôûãõëü','ACEIOUAEIOUAEIOUAOEUaceiouaeiouaeiouaoeu'))
=
UPPER(translate(TABLEB.N_STRING,
'ÁÇÉÍÓÚÀÈÌÒÙÂÊÎÔÛÃÕËÜáçéíóúàèìòùâêîôûãõëü','ACEIOUAEIOUAEIOUAOEUaceiouaeiouaeiouaoeu')
使用函数需要超过 3 分钟(80k + 行)
SELECT TABLE_A.STRING_X
FROM TABLE_A
INNER JOIN TABLE_B ON TABLE_B.ID = TABLE_A.IDTB
WHERE
FUNCTION_X(TABLE_A.STRING_X) = FUNCTION_X(TABLE_B.N_STRING)
我不知道是什么让它如此沉重。
解决方案
如果您的第一个查询,查询中的UPPER(UPPER(translate(...)))
内联只需要 5 秒并且表很大,我会看看您是否有一个基于函数的索引,在一个或两个表上都有这些函数。
您可能知道,索引存储数据的排序版本,以便可以快速找到行。但它们仅在您搜索在索引中排序的数据时才有用。(想想一本书中的索引,其中关键字按字母顺序排序——对于搜索特定单词很有用,对于查找以字母“r”结尾的单词的引用不太有用)。
如果有一个基于函数的索引UPPER(UPPER(translate(...)))
有助于您的原始查询,那么当您的查询指定时,您将失去好处FUNCTION_X(...)
。Oracle 不够聪明,无法意识到它们是相同的功能。您需要根据您在查询中实际使用的表达式创建基于函数的索引 - 即 on FUNCTION_X(...)
。
此外,您可以通过告诉 Oracle 您的函数是确定性的(即,始终为相同的输入返回相同的值)并打算在 SQL 查询中使用来提高性能。因此,除了基于函数的索引之外,更好的函数定义是:
create or replace FUNCTION FUNCTION_X
(
N_STRING IN VARCHAR2
) RETURN VARCHAR2
DETERMINISTIC -- add this
AS
PRAGMA UDF; -- add this too
BEGIN
RETURN UPPER(translate(N_STRING, 'ÁÇÉÍÓÚÀÈÌÒÙÂÊÎÔÛÃÕËÜáçéíóúàèìòùâêîôûãõëü','ACEIOUAEIOUAEIOUAOEUaceiouaeiouaeiouaoeu'));
END FUNCTION_X;
推荐阅读
- r - data.table 链接不会创建新变量
- php - Wordpress 多站点 - 一个域页脚中的菜单引用多站点上不同站点的菜单
- html - 将 Angular 组件相互传递
- mysql - 从 MySQL 读取 JSON 数据的最快方法
- git - 无法在 pydroid 中安装 git。请帮忙
- spring-boot - 如何在 Spring Boot Camel 项目中测试 Camel - 所有 @EndpointInject 均为空但 @Autowired 工作?
- azure - Azure 关联 ID 和请求 ID
- java - 是否有任何 API 可以使用 WebdataRocks 创建“主 - 子报告”
- angular - 如何在 spartacus 应用程序中知道 gigya 屏幕设置上更新了哪些首选项?
- android - 无法从 Android Material 滑块中删除填充