Wayne


Calendar
February | ||||||
---|---|---|---|---|---|---|
Sun | Mon | Tue | Wed | Thu | Fri | Sat |
29 | 30 | 31 | 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 1 | 2 | 3 | 4 |

Categories

Search

Random Posts

Counter
362395

Hot Posts

New Comments

New Messages

Links

RSS

遇到一段跑起来费解的代码
Wayne
posted @ Thu, 12 Jan 2012 17:25:30 +0000
in Experience
, 2209 readers
今天校准数据库的时候,发现了一个执行结果不同的现象。经过定位,发现问题出在下面这段代码上。这段代码的执行结果被一个v_request_num的变量所左右。 v_request_num 越小,最后的结果就越少, v_request_num 越大,最后的结果就越多。如果说单次执行的话,这个是废话。但多次执行,直到将表中数据计算完毕后的结果也是这样,着实费解。
代码如下:
/********************************************************************************************/ /* 最小阀值 */ /********************************************************************************************/ begin select min(index_value) into v_min_value from indexvalue where exec_index = v_exec_index; exception when others then v_error_no := 23122003; p_error_info := '[23122003]取最小index_value失败' || ' v_exec_index = ' || v_exec_index; return v_error_no; end; /********************************************************************************************/ /* 取已执行流水号 */ /********************************************************************************************/ begin select nvl(count(*), 0) into v_count from icsentrustno where exec_index = v_exec_index and branch_no = 0; exception when others then null; end; if v_count = 0 then begin insert into icsentrustno values(v_exec_index, 0, 0); exception when others then v_error_no := 23122003; p_error_info := '[23122003]插入流水号表失败' || 'exec_index = ' || v_exec_index; return v_error_no; end; else begin select record_id into v_record_id from icsentrustno where exec_index = v_exec_index and branch_no = 0; exception when others then v_error_no := 23122004; p_error_info := '[23122004]执行流水号不存在' || 'exec_index = ' || v_exec_index; return v_error_no; end; end if; /********************************************************************************************/ /*重置起始流水号 */ /********************************************************************************************/ begin select nvl(min(record_id),0) into v_beginrecord_id from entrust; exception when others then v_error_no := 23122013; p_error_info := '[23122013]取最小流水号失败' || ' v_exec_index = ' || v_exec_index; return v_error_no; end; if v_record_id < v_beginrecord_id then begin update icsentrustno set record_id = v_beginrecord_id - 1 where exec_index = v_exec_index; exception when others then v_error_no := 23122013; p_error_info := '[23122013]更新执行流水号表失败' || ' v_exec_index = ' || v_exec_index; return v_error_no; end; v_record_id := v_beginrecord_id - 1; end if; /********************************************************************************************/ /* 取执行结束流水号 */ /********************************************************************************************/ begin select nvl(MAX(record_id),0) into v_endrecord_id from entrust; exception when others then v_error_no := 23122007; p_error_info := '[23122007]取执行结束流水号失败' || ' 执行指标: ' || v_exec_index; return v_error_no; end; if v_endrecord_id = v_record_id then --没有新增流水 return 0; end if; if v_request_num <> 0 and v_endrecord_id > (v_record_id + v_request_num) then v_endrecord_id := v_record_id + v_request_num; --只取v_request_num条记录 end if; --取配置计算时间设置 begin select nvl(int_config, 15) into v_up_time from consysconfig where config_no = 4121; exception when others then v_up_time := 15; end; begin select cast(nvl(str_config, 1.02) as number(19,2)) into v_ratio from consysconfig where config_no = 4120; exception when others then v_ratio := 1.02; end; begin select nvl(int_config, -1) into v_diff from consysconfig t where config_no = 4207; exception when others then v_diff := -1; end; /********************************************************************************************/ /* 以下 计算指标,记录超标流水,置执行流水号 */ /********************************************************************************************/ begin select min(entrust_time),max(entrust_time) into v_min_entrust_time,v_max_entrust_time from entrust where record_id > v_record_id and record_id <= v_endrecord_id and entrust_time between 0 and 150000; exception when others then v_error_no := 22702307; p_error_info := '[22702307]获取区间最小及最大委托时间失败' || ' 执行指标: ' || v_exec_index; return v_error_no; end; v_begin_time := case when v_min_entrust_time - v_up_time*60 < 0 then 0 else fn_gettime_diffbyminute(v_min_entrust_time, v_up_time) end; v_end_time := v_max_entrust_time; begin insert into t_231220 select * from entrust where entrust_time >= 92000 and entrust_time between v_begin_time and v_end_time and stock_type not in ('D','F') and abs(entrust_amount * entrust_price) >= v_min_value and entrust_type in ('0','6','7','9') and entrust_prop = '0'; exception when others then v_error_no := 22702307; p_error_info := '[22702307]插入临时表[t_231220]失败' || ' 执行指标: ' || v_exec_index; return v_error_no; end; declare cursor cur_record is select record_id, oc_date, entrust_time, client_id, fund_account, branch_no, operator_no, exchange_type, stock_code, entrust_price, entrust_bs, entrust_amount, entrust_price, entrust_type from t_231220 a where record_id > v_record_id and record_id <= v_endrecord_id and exists(select 1 from t_231220 b where b.fund_account <> a.fund_account and b.exchange_type = a.exchange_type and b.stock_code = a.stock_code and b.entrust_time between case when a.entrust_time - v_up_time*60 <0 then 0 else fn_gettime_diffbyminute(a.entrust_time,v_up_time) end and fn_gettime_diffbyminute(a.entrust_time,-v_up_time) and b.entrust_bs <> a.entrust_bs and b.entrust_bs = case a.entrust_bs when '1' then '2' when '2' then '1' end and (b.entrust_type = case a.entrust_type when '6' then '0' when '7' then '0' when '9' then '0' end or b.entrust_type = case a.entrust_type when '0' then '6' end or b.entrust_type = case a.entrust_type when '0' then '7' end or b.entrust_type = case a.entrust_type when '0' then '9' end) and (case when b.entrust_price > a.entrust_price then b.entrust_price/a.entrust_price else a.entrust_price/b.entrust_price end) < v_ratio and (v_diff = -1 or ABS(b.entrust_amount - a.entrust_amount) <= v_diff)) order by record_id;
这里entrust_time是个时间转化出来的number类型,格式是yyyymmdd,8位整数。
v_up_time的单位是分钟。
fn_gettime_diffbyminute(entrust_time,v_up_time) 的作用是得到 entrust_time前 v_up_time的时间,比如当entrust_time为150000 (15点整),v_up_time为10 (10分钟)时,这个函数的结果就是 145000 (14点50分)。类似的,参数变成-v_up_time,就是取entrust_time的后v_up_time的时间,比如说151000。
手动执行的时候,删掉了record_id,相当于从0到最大。如果直接设置v_request_num 这个步长变量到很大,也可以达到同样效果。程序自己跑的话,v_request_num 为500。
步长非常大,比如说2000000,跟步长500相比,唯一影响在于游标取值时的record_id条件上, 可这个条件为什么会导致最后结果变少了呢?
我错了…… 我光被最后一个游标的条件吸引了注意力,却没注意到最开始取 v_min_entrust_time 和 v_max_entrust_time 时也用到了 record_id。 前面就用到了,导致 t_231220 中的记录集差很多,那么自然执行结果也差很多…… 这么显而易见的问题,居然给忽视了