需要进行数据库查询或逻辑优化

时间:2016-11-18 10:17:56

标签: sql oracle stored-procedures database-performance

我在2百万条记录上执行以下查询(oracle11g)。这需要大约2.2秒。

我的疑问:

select SUBSCRIBER_NUM, SUBSCRIBER_STATUS, P_ID
from C_S_FORWARD_INFO
where '07052620' LIKE SUBSCRIBER_NUM || '%'
  and SCP_VER = 1

以下是我的表格。

CREATE TABLE C_S_FORWARD_INFO 
  ( 
    SUBSCRIBER_NUM                  VARCHAR2(30 BYTE) NOT NULL, 
    P_ID                            NUMBER, 
  SUBSCRIBER_STATUS NUMBER(1,0) DEFAULT 0 NOT NULL,
    ACCOUNT_NUMBER                  INTEGER NOT NULL,   
    MAJOR_VERSION_ID                NUMBER(10,0) DEFAULT 1 NOT NULL, 
    MINOR_VERSION_ID             NUMBER(10,0) DEFAULT 1 NOT NULL, 
    SCP_VER                         NUMBER(1,0) DEFAULT 0 CHECK (SCP_VER IN (0,1)), 
  );

ALTER TABLE C_S_FORWARD_INFO ADD CONSTRAINT C_S_FORWARD_INFO_PK
PRIMARY KEY (SUBSCRIBER_NUM,ACCOUNT_NUMBER,MAJOR_VERSION_ID, MINOR_VERSION_ID);

DB Records(例如,实际上它有2百万条记录)

Row 1 => 07052620,1,1,10, 1, 1, 1;
Row 2 => 0705262,2,1,10, 1, 1, 1;
Row 3 => 070526,3,1,10, 1, 1, 1;
Row 4 => 070526200001,4, 1,10, 1, 1, 1;
Row 5 => 07052,5,1,10, 1, 1, 1;
......

预期结果:第1行(我通过上面的查询获得此结果,逻辑:从最长匹配开始直到'07052620')

如何优化上述查询。或编写任何其他逻辑以在.2秒内获得预期结果。在我的查询'07052620'中,动态数字作为存储过程中的输入获取。

20/11 - 更新:

我在下面尝试过(VAR_CALLING_NUM = 07052620):

while var1<=len LOOP 
temp1 := SUBSTR(VAR_CALLING_NUM, 1, var1); 
temp1 := concat('''',temp1); 
temp1 := concat(temp1,''''); 
temp6 := temp6 || temp1 || ',' ; 
var1:=var1+1; 
END LOOP; 
temp6 := SUBSTR(temp6, 1,length(temp6)-1);

select SUBSCRIBER_NUM, SUBSCRIBER_STATUS, P_ID from C_S_FORWARD_INFO where SUBSCRIBER_NUM IN ( temp6 ) and SCP_VER = 1 order by length(subscriber_num) desc; 

但这不是给我结果。看起来查询没有动态地采用temp6。请帮忙

3 个答案:

答案 0 :(得分:0)

以下查询将子查询添加到原始尝试中,该子查询将结果限制为匹配但也限制为最长匹配的结果。它会随意返回一条记录,但如果你想返回最长匹配的关系,可以很容易地修改它。

select SUBSCRIBER_NUM,
       SUBSCRIBER_STATUS,
       P_ID
from C_S_FORWARD_INFO
where '07052620' LIKE SUBSCRIBER_NUM || '%'  and
      SCP_VER = 1 and
LENGTH(SUBSCRIBER_NUM) = (select max(length(SUBSCRIBER_NUM)) from C_S_FORWARD_INFO
                          where '07052620' like SUBSCRIBER_NUM || '%' and SCP_VER = 1)
offset 0 rows fetch next 1 rows only;

答案 1 :(得分:0)

如果这是您的查询:

select SUBSCRIBER_NUM, SUBSCRIBER_STATUS, P_ID
from C_S_FORWARD_INFO
where '07052620' LIKE SUBSCRIBER_NUM || '%' and
      SCP_VER = 1;

然后,我建议将其重写为:

select SUBSCRIBER_NUM, SUBSCRIBER_STATUS, P_ID
from C_S_FORWARD_INFO
where SUBSCRIBER_NUM IN ('0', '07', '070', '0705', '07052', '070526', '0705262', '07052620') and
      SCP_VER = 1
order by length(subscriber_num) desc
fetch first 1 row only;

然后,在(SCP_VER, SUBSCRIBER_NUM)上添加索引:

create index idx_forwardinfo_2 on c_s_forward_info(SCP_VER, SUBSCRIBER_NUM);

答案 2 :(得分:0)

这可能会或可能不会对您的效果问题有所帮助:

Microsoft Windows Storage Server 2008 R2 Essentials 6.1.7601 Service Pack 1

我建议您在以下列的c_s_forward_info上有一个多列索引:(subscriber_num,scp_ver,subscriber_status,p_id)

这应该有希望允许查询仅针对索引运行。

查询的工作原理是首先将您传递的字符串分解为要再次匹配的各种组合(这是字符串中的前N个字符,其中N是1和字符串长度之间的任何值传入)。

一旦我们将这些字符串与之匹配,我们就可以直接将它们连接到订阅者列,如果它认为更有效,则优化器将允许优化器使用索引。

然后,我们可以计算row_number()(或者如果要显示与最高优先级连接行匹配的所有行,则可能是dense_rank()),然后选择顶行。