报表优化-------根据IP地址对比起始IP和结束IP找到相应的地域(判断两个IP地址)
2017-06-26 21:18
381 查看
这个报表很慢,通过测试发现慢的原因是在关联IP地址库上表较慢,这里需要通过给定的IP地址,对比IP地址起始IP和结束IP范围找到所在区域。
通过自定义函数直接去关联或者是通过拆分对每个值去关联,这两张方式都是十几分钟,如果查询的数据量大的话直接宕机。但是不关联IP地址库的话5秒就出结果。
我最终返回的数据有将近30万的数据,IP地址库有60多万数据。最终通过两种方式处理,方式一:32秒就出数据。方式二:16秒就出数据。
原sql:
1、函数:
2、更新dim_ip_class 表
3、进行不等值连接
方式二:
创建一个函数转化为数字,由于上一个函数经过了列转行,通过测试函数F_IP_TO_NUMBER比get_ipaddress_func快2分钟:
1.创建函数
2、通过函数更新数据
通过自定义函数直接去关联或者是通过拆分对每个值去关联,这两张方式都是十几分钟,如果查询的数据量大的话直接宕机。但是不关联IP地址库的话5秒就出结果。
我最终返回的数据有将近30万的数据,IP地址库有60多万数据。最终通过两种方式处理,方式一:32秒就出数据。方式二:16秒就出数据。
原sql:
select s.ip_address ip , dp.province || dp.city || dp.county ip_address from data_etl.t_statistics s left outer join dim_ip_class dp on( to_number(regexp_substr(s.ip_address, '[^.]+', 1, 1)) between to_number(regexp_substr(dp.ip_start , '[^.]+', 1, 1)) and to_number(regexp_substr(dp.ip_end, '[^.]+', 1, 1)) and to_number(regexp_substr(s.ip_address, '[^.]+', 1, 2)) between to_number(regexp_substr(dp.ip_end, '[^.]+', 1, 2)) and to_number(regexp_substr(dp.ip_end, '[^.]+', 1, 2)) and to_number(regexp_substr(s.ip_address, '[^.]+', 1, 3)) between to_number(regexp_substr(dp.ip_start, '[^.]+', 1, 3)) and to_number(regexp_substr(dp.ip_end, '[^.]+', 1, 3)) and to_number(regexp_substr(s.ip_address, '[^.]+', 1, 4)) between to_number(regexp_substr(dp.ip_start, '[^.]+', 1, 4)) and to_number(regexp_substr(dp.ip_end, '[^.]+', 1, 4)) );或者
select s.ip_address ip, dp.province || dp.city || dp.county ip_address from data_etl.t_statistics s left outer join dim_ip_class dp on (get_ipaddress_func(s.ip_address) between get_ipaddress_func(dp.ipstart) and get_ipaddress_func(dp.ipend));
1、函数:
create or replace function get_ipaddress_func(p_ip varchar2) return varchar2 as l_cnt varchar2(100); l_ip varchar2(100); begin l_ip :=p_ip; select listagg(subring) WITHIN GROUP(ORDER BY rn) into l_cnt from (select level rn, lpad(regexp_substr('' || l_ip || '', '[^.]+', 1, level), 3, 0) subring from dual connect by level <= 4); return l_cnt; end; / PS:还有一种补0的方式: select LPAD(SUBSTR('012.034.6.110', 1, (INSTR('012.034.6.110', '.', 1, 1) - 1)), 3, '0') || '.' || LPAD(SUBSTR('012.034.6.110', INSTR('012.034.6.110', '.', 1, 1) + 1, INSTR('012.034.6.110', '.', 1, 2) - INSTR('012.034.6.110', '.', 1, 1) - 1), 3, '0') || '.' || LPAD(SUBSTR('012.034.6.110', INSTR('012.034.6.110', '.', 1, 2) + 1, INSTR('012.034.6.110', '.', 1, 3) - INSTR('012.034.6.110', '.', 1, 2) - 1), 3, '0') || '.' || LPAD(SUBSTR('012.034.6.110', INSTR('012.034.6.110', '.', 1, 3) + 1), 3, '0') from dual SUBSTRING --------------- 012.034.006.110
2、更新dim_ip_class 表
update dim_ip_class s set s.ipstart=get_ipaddress_func (ipstart),s.ipend=get_ipaddress_func(ipend); commit;update dim_ip_class s set s.ipstart=get_ipaddress_func (ipstart),s.ipend=get_ipaddress_func(ipend); commit;
3、进行不等值连接
select s.ip_address ip , dp.province || dp.city || dp.county ip_address from data_etl.t_statistics s left outer join dim_ip_class dp on (get_ipaddress_func(s.ip_address) between dp.ipstart and dp.ipend);
方式二:
创建一个函数转化为数字,由于上一个函数经过了列转行,通过测试函数F_IP_TO_NUMBER比get_ipaddress_func快2分钟:
1.创建函数
create or replace function F_IP_TO_NUMBER(p_ipaddress in varchar2) return number deterministic as l_result number; begin select to_number(substr(p_ipaddress, 1, instr(p_ipaddress, '.', 1, 1) - 1)) * 255 * 255 * 255 * 255 * 1000 + to_number(substr(p_ipaddress, instr(p_ipaddress, '.', 1, 1) + 1, instr(p_ipaddress, '.', 1, 2) - instr(p_ipaddress, '.', 1, 1) - 1)) * 255 * 255 * 255 * 100 + to_number(substr(p_ipaddress, instr(p_ipaddress, '.', 1, 2) + 1, instr(p_ipaddress, '.', 1, 3) - instr(p_ipaddress, '.', 1, 2) - 1)) * 255 * 255 * 10 + to_number(substr(p_ipaddress, instr(p_ipaddress, '.', 1, 3) + 1, length(p_ipaddress) - instr(p_ipaddress, '.', 1, 3))) * 255 + 1 into l_result from dual; return l_result; end; /
2、通过函数更新数据
SQL> alter table dim_ip_class add ip_start_tag number; Table altered SQL> alter table dim_ip_class add ip_end_tag number; Table altered SQL> update dim_ip_class set ip_start_tag=F_IP_TO_NUMBER(ipstart), 2 ip_end_tag=F_IP_TO_NUMBER(ipend); 628160 rows updated SQL> commit; Commit complete
相关文章推荐
- 根据ip/掩码格式地址段得到起始地址和结束地址
- JAVA代码根据IP/掩码位数格式地址段得到起始地址和结束地址,可用IP数量,掩码
- 根据ip和子网掩码判断两个ip是否在同一个子网
- Java获取客户端ip以及根据ip查询到相应的ip地址
- 使用php根据起始ip地址和掩码 计算广播地址(网段结束地址)
- Go实战--golang中获取公网ip、查看内网ip、检测ip类型、校验ip区间、ip地址string和int转换、根据ip判断地区国家运营商等
- 生成二维码 加密解密类 TABLE转换成实体、TABLE转换成实体集合(可转换成对象和值类型) COOKIE帮助类 数据类型转换 截取字符串 根据IP获取地点 生成随机字符 UNIX时间转换为DATETIME\DATETIME转换为UNIXTIME 是否包含中文 生成秘钥方式之一 计算某一年 某一周 的起始时间和结束时间
- PHP获取IP地址及根据IP判断城市实现城市切换或跳转
- 根据起始IP和结束IP输出指定范围的IP
- PHP获取IP地址及根据IP判断城市实…
- c# 根据IP判断地址类
- 如何实现网站根据ip判断地区 自动跳转到所属地区页面【PHP版】
- 计算机 网关 子网 网段 ip地址解释 如何判断两个IP地址在同一网段
- RS报表中根据变量比较大小来判断颜色
- 如判断这两个IP是否属于同一网段?
- .NET读取QQWry.Dat 纯真版ip数据库(根据ip判断国家)
- boj 1334 思路混乱 弄了2个下午。。太笨了。。。 思路:先按起始时间排序,起始时间相同的,只保留结束时间最长的,然后判断。
- 判断两个IP地址是不是在同一个网段
- 【java】根据开始时间、结束时间得到两个时间段内所有的日期
- 根据IP地址,找到交换机上相对应的端口