如何强制 where 子句中的函数在 oracle 中执行一次?

2024-01-15

我正在尝试根据 IP 地址查询相当大的 IP/城市(3,000,000 多行)表。我的源 IP 地址是点分符号,例如 127.0.0.1,表有两个字段存储为整数,例如 2130706433。因此,我需要将点分符号转换为我的 where 子句中的整数,如下所示;

select get_ip_integer('74.253.103.98') ,icb.*,icl.* 
from ip_city_block icb, ip_city_location icl 
where get_ip_integer('74.253.103.98') between  icb.startipnum and  icb.endipnum  and
      icl.locid = icb.locid;

在相当快的数据库上,此查询需要 4 ~(4.33) 秒以上。以下查询需要 0.062 秒;

select 1258121058,icb.*,icl.* 
from ip_city_block icb, ip_city_location icl 
where icb.startipnum <= 1258121058 and  icb.endipnum >= 1258121058 and
      icl.locid = icb.locid;

唯一的区别是我将函数 get_ip_integer 替换为函数返回的值。如果我所做的只是一次查找,我会执行第二个查询并完成它,但我没有。

我实际上想加入另一个包含许多点格式 IP 地址的表,而当我这样做时,它需要很长时间。为了好玩我也尝试过;

select ip_integer ,icb.*,icl.* 
from (select get_ip_integer('74.253.103.98') ip_integer from dual),ip_city_block icb, ip_city_location icl 
where icb.startipnum <= ip_integer and  icb.endipnum >= ip_integer and
      icl.locid = icb.locid;

这也花了大约 4.33 秒。

所以问题是如何强制 get_ip_integer 函数只执行一次并使用结果进行比较?

我将函数更新为确定性,它似乎对原始查询有所帮助,但更复杂的查询在性能方面仍然无法使用。这里是;

SELECT COUNTRY, REGION,CITY, WEBLOG_USERID, WEBLOG_IP, WEBLOG_COUNT 
FROM (
  select WEBLOG_USERID,WEBLOG_IP,get_ip_integer(WEBLOG_IP) ip_integer,count(*) WEBLOG_COUNT 
  from weblog 
  where weblog_date > '20130217' 
  group by WEBLOG_USERID,weblog_ip
),ip_city_block icb, ip_city_location icl 
where ip_integer between icb.startipnum and icb.endipnum and icl.locid = icb.locid
ORDER BY 1,2,3;

对此有什么想法吗?

经过我自己的一点思考,我想出了这个,虽然不是盲目的快,但它是可以接受的;

SELECT COUNTRY, REGION,CITY, WEBLOG_USERID, WEBLOG_IP, WEBLOG_COUNT 
FROM (
  select WEBLOG_USERID,WEBLOG_IP, count(*) WEBLOG_COUNT 
  from weblog 
  where weblog_date > '20130000' 
  group by WEBLOG_USERID,weblog_ip
),ip_city_block icb, ip_city_location icl 
where get_ip_integer(WEBLOG_IP) between icb.startipnum and icb.endipnum and icl.locid = icb.locid
ORDER BY 1,2,3;

为什么要使用 PL/SQL 来完成此任务?根据你所说的,你正在做一些数学,为什么不直接用 SQL 来做呢?这也可以通过 INSTR 和 SUBSTR 的组合实现,但使用 REGEXP_SUBSTR 看起来更漂亮。

select to_number(regexp_substr(ip, '[^.]+', 1, 1)) * power(2,24)
        + to_number(regexp_substr(ip, '[^.]+', 1, 2)) * power(2,16)
        + to_number(regexp_substr(ip, '[^.]+', 1, 3)) * power(2,8)
        + to_number(regexp_substr(ip, '[^.]+', 1, 4))
     , icb.*
     , icl.* 
  from ip_city_block icb
  join ip_city_location icl
    on icl.locid = icb.locid  
 where to_number(regexp_substr(ip, '[^.]+', 1, 1)) * power(2,24)
        + to_number(regexp_substr(ip, '[^.]+', 1, 2)) * power(2,16)
        + to_number(regexp_substr(ip, '[^.]+', 1, 3)) * power(2,8)
        + to_number(regexp_substr(ip, '[^.]+', 1, 4))
       between icb.startipnum and icb.endipnum

REGEXP_SUBSTR 输出的 SQL Fiddle 演示 http://www.sqlfiddle.com/#!4/d41d8/7528

If you have要在 PL/SQL 中执行此操作,您应该做两件事:

  1. 看看你是否可以将你的函数声明为确定性的 http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/create_function.htm#LNPLS01370.
  2. 尝试并利用子查询缓存 http://www.oracle.com/technetwork/issue-archive/2011/11-sep/o51asktom-453438.html.

看起来好像您已经在执行 2,但您可以尝试使用WITH 子句来扩展它:

with the_ip as ( select get_ip_integer('74.253.103.98') as ip from dual )
select the_ip.ip
     , icb.*
     , icl.* 
  from ip_city_block icb
  join ip_city_location icl
    on icl.locid = icb.locid
  join the_ip
    on the_ip.ip between icb.startipnum and icb.endipnum
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何强制 where 子句中的函数在 oracle 中执行一次? 的相关文章

  • 如何在 Pro*C 查询中指定变量表达式列表?

    我尝试优化的 Pro C 查询出现问题 解释一下 我们的应用程序在一个巨大的数据库中搜索行 这些行存在于多种语言中 旧代码为数组中的每种语言选择一行 现在 由于这些查询是我们应用程序中最耗时的部分 因此我只想进行一个直接写入数组的查询 语言
  • MySQL 中有“connect by”替代方案吗?

    如果我使用 Oracle 有connect by可用于创建分层查询的关键字 目前我正在一个项目中使用MySQL 我想知道是否有替代方案connect by在 MySQL 中 我尝试过谷歌 但到目前为止还没有结果 我想要实现的是通过一个查询从
  • 如何查看任意 Oracle 会话正在使用的事务隔离级别

    我试图找出特定会话 不是我自己的会话 在 Oracle 服务器上的隔离级别 有 v 视图可以得到这个吗 您可以在中测试位 28flag列于v transaction 1 http forums oracle com forums threa
  • Oracle中如何选择前100行?

    我的要求是获取每个客户的最新订单 然后获取前100条记录 我编写了一个如下查询来获取每个客户的最新订单 内部查询工作正常 但我不知道如何根据结果获得前 100 名 SELECT FROM SELECT id client id ROW NU
  • oracle to_date 转换显示文字与字符串格式不匹配

    如果我使用 unixtime 转换器 我会得到 2005 年 5 月 31 日星期二 16 23 17 GMT 1117556597 如果我运行以下查询 则会收到错误 文字与字符串格式不匹配 这是为什么 select to date 111
  • Postgresql存储过程中基于会话的全局变量?

    在 Oracle 的 PL SQL 中 我可以使用包定义创建基于会话的全局变量 对于 Postgresql 的 PLpg SQL 这似乎是不可能的 因为没有包 只有独立的过程和函数 以下是 PL SQL 将 g spool key 声明为全
  • SQL使用多个/相关列计算项目频率?

    我对 SQL 完全陌生 并且阅读了有关 SQL 的 StackOverflow 帖子来尝试弄清楚这一点 以及其他来源 但无法在 SQL 中执行此操作 开始 我有一个 3 列和数千行的表 其中包含前 2 列的数据 第三列当前为空 我需要根据第
  • 如何登录Oracle数据库?

    我对 Oracle 数据库中常用的日志记录方法感兴趣 我们的方法如下 我们为要记录的表创建一个日志表 日志表包含原始表的所有列以及一些特殊字段 包括时间戳 修改类型 插入 更新 删除 修改者的 id 原始表上的触发器为每次插入和删除创建一个
  • 在 plsql 中立即执行

    如何从这段代码中得到结果 EXECUTE IMMEDIATE SELECT FROM table name through for loop 通常的方法看起来像这样 for items in select from this table l
  • 以无法破坏的方式限制表中允许的记录数量

    我们有一个 Web 应用程序 Grails 我们将根据用户数量为其出售许可证 数据库 Oracle 10g 中有一个表保存用户 客户将托管自己的软件和数据库副本 有人可以建议一些策略来限制允许存在于用户表中的记录数量 从而使客户无法合理地破
  • 如何打印Oracle中过程的定义?

    oracle中有没有办法查看过程的结构是什么 我正在尝试记录并运行程序 并希望将实际的程序结构存储在我的日志中 您可以查询ALL SOURCE table SELECT text FROM all source WHERE owner lt
  • 创建 SYS_REFCURSOR 并将其作为输入参数从 Java 传递给 Oracle 过程

    我必须与具有 SYS REFCURSOR 作为输入参数的外部 Oracle 过程进行通信 过程 merge objects varchar2 中的 p table name p id array 中 varchar2 SYS REFCURS
  • APEX:从临时表下载 BLOB

    我正在尝试使用 Oracle APEX 4 1 1 构建一个简单的查看应用程序 要显示的信息位于与包含 APEX 应用程序访问的架构的数据库不同的数据库上的表中 使用视图 View 访问此远程表 远程表视图 和数据库链接 视图按预期工作 包
  • 使用 xmlagg 时出现子查询错误和太多值

    我在连接许多大型表中的所有数据时遇到问题 我昨天对此提出了问题 但不幸的是 listagg 似乎不是一个好的选择 链接子查询返回多行 https stackoverflow com questions 54651144 subquery r
  • 当我输入 dateadd 或 datediff 代码时,我总是收到此错误“ORA-00904“DATEADD”无效标识符。”

    我有一个大学项目 并且有一个包含入院和出院日期属性的患者表 我需要删除超过 7 年的记录 我使用了以下代码 delete from patient where dis date gt datedadd yy 7 getdate 我收到错误
  • oracle中的区间函数

    Query SELECT INTERVAL 300 month INTERVAL 54 2 year to month INTERVAL 11 12 10 1234567 hour to second FROM DUAL 上述查询的输出是
  • 如何在oracle中使用2位小数进行舍入,如下所示

    您好 我有要求 如果我使用舍入函数 则四舍五入为小数点后两位 它会四舍五入 但如果第三个小数小于 5 则不会四舍五入 我的要求是小数点后第三位和小数第二位应该四舍五入 是否可以 eg 17 813 need to be 17 82 20 1
  • ora-12528: TNS:Listener: 所有适当的实例都阻止新连接

    当我尝试连接到数据库时收到此错误 ora 12528 TNS Listener 所有适当的实例都阻止新连接 我尝试了以下操作 但没有成功 停止和启动侦听器 关闭和启动数据库 重新启动 oracle 服务 我该如何解决这个问题 您可能会遇到网
  • count(distinct) over (partition by... 在 Oracle SQL 中不起作用

    我想数一下distinct day number过去 30 天 但是 distinct 函数不能与over 如果我删除distinct 它会给我总数day number but day number可以有很多重复的 所以这就是为什么我想添加
  • 每组最大 n 个 SQL 查询的高性能方法

    我正在尝试构建一个基础设施 以便根据需要快速运行回归 从包含我们网络服务器上所有历史活动的数据库中提取 apache 请求 为了通过确保我们仍然回归来自较小客户的请求来提高覆盖范围 我想通过为每个客户检索最多 n 个 为了这个问题 假设 1

随机推荐