select a.*,b.address from vinfo_visit_log_temp a left join address_ip b on to_number(getAreaByIp(a.visit_ip)) between b.startip and b.endipvinfo_visit_log_temp 表中数据中有15w条数据(a.visit_ip是varchar2,比如192.168.0.102,getAreaByIp函数为自定义,是计算出ip对应的number)
address_ip中有26w条数据,表结构 startip:number,endip:number,address:varchar2(地方名,比如河南省)现在这条sql语句的目的是查出vinfo_visit_log_temp每条访问记录的来源地方名有没有执行效率更高些的sql语句

解决方案 »

  1.   

    呵呵,应该就是慢在
    to_number(getAreaByIp(a.visit_ip)) between b.startip and b.endip
    上了,全表扫描了a表,没有调用索引
      

  2.   

    将执行计划贴出来看看吧..explain plan for 
    select a.*,b.address from vinfo_visit_log_temp a left join address_ip b on to_number(getAreaByIp(a.visit_ip)) between b.startip and b.endip
    /
    @?/rdbms/admin/utlxplp.sqlOracle数据库不建议使用ansi sql, 有些时候ansi sql的执行计划比较难处理..
      

  3.   

    就是因为你的这个getAreaByIp(a.visit_ip)的自定义函数,写在了条件的数据列上
    这样导致的结果就是a表中的每行数据的visit_ip都要经过运算才可以和后面的条件进行比较
    加上你的表又大所以每行都作一次getAreaByIp(a.visit_ip)运算,时间可想而知。向你这种情况对a.visit_ip建立索引是无效的。优化方法:
    1)考虑a表中是否有其它栏位可以作为条件过滤一些资料行,看你的情况似乎不适用
    2)在a表中添加一个栏位adress,或者是添加一个栏位tip
       在a表创建Trigger,通过to_number(getAreaByIp(:new.visit_ip))运算写入栏位tip
       甚至可以直接得到地址写入address建议考虑第二种方法。这种做法是将运算分散到每次Insert中而不是在查询中才去运算。可以提高查询时间。
       如果担心大批量插入速度受到影响,也可以写job定时运行更新a表中创建的tip或address栏位
      

  4.   

    谢谢各位的讨论,
    我狂搜索,慢的原因有两个:
    1:to_number(getAreaByIp(a.visit_ip)) 这个
    2:是left join 左连接采用yqwd911(windy) 的方法2。再次感谢!