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

Sql 需要数据库查询或逻辑优化,sql,oracle,stored-procedures,database-performance,Sql,Oracle,Stored Procedures,Database Performance,我在200万条记录上执行下面的查询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

我在200万条记录上执行下面的查询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记录例如,在现实中它有200万条记录

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”

如何优化上述查询。或编写任何其他逻辑以在0.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。请帮助

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

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;
如果这是您的查询:

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版本、订户编号上添加索引:


这可能有助于解决性能问题,也可能没有:

WITH pred_vals AS (SELECT SUBSTR('07052620', 1, LENGTH('07052620') + 1 - LEVEL) str,
                          LEVEL priority
                   FROM   dual
                   CONNECT BY LEVEL <= LENGTH('07052620')),
     main_join AS (SELECT fi.subscriber_num,
                          fi.subscriber_status,
                          fi.p_id
                          row_number() OVER (ORDER BY pv.priority) rn
                   FROM   c_s_forward_info fi
                          INNER JOIN pred_vals pv ON (fi.subscriber_num = pv.str)
                   WHERE  scp_ver = 1)
SELECT subscriber_num,
       subscriber_status,
       p_id
FROM   main_join
WHERE  rn = 1;
我建议您在以下列的c_s_forward_info上有一个多列索引:subscriber_num、scp_ver、subscriber_status、p_id

这将有望允许查询仅针对索引运行

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

一旦我们有了这些字符串来匹配,我们就可以直接将它们连接到订户列,这将允许优化器使用索引,如果它认为这样做更有效的话


然后,如果您想显示与最高优先级连接行匹配的所有行,然后选择最上面的行,我们可以计算行数或密集排列。

谢谢。让我试试。只有一件事,我是数据库新手,我如何才能将索引添加到订阅者_NUM列。需要运行任何查询吗?很抱歉,如果您发现这个问题。我应该执行:在C_S_FORWARD_INFO SUBSCRIBER_NUM上创建索引C_S_FORWARD_INFO_IDX吗index@TimBiegeleisen:我没有使用您的查询获得预期结果。案例:如果DB中不存在第1行,则我的预期结果是第2行,因为0705262是最长的以匹配开头。你能看看吗。使用您的查询,我得到的第4行不是Expected。如果您真的只想要第一条记录,那么通配符有什么意义?蒂姆·比格莱森:我需要从最长的比赛开始。通过平等是不可能的。在查询中,我们有其中的“07052620”,因此我预期的行选择是0、07、070、0705、07052、070526、0705262、07052620,由于07052620是最长的匹配,我将选择此项。您当前的查询存在逻辑问题,此外还有优化问题。您希望解决哪一个问题?您希望表中的行有多大比例满足这些条件?此外,数据集中的订户号码有多少唯一值,以及输入号码的变化程度如何?可能是0吗?还是至少会有这么多字符?@David Aldridge:Query应该给我第1、2、3和5行,而不应该给我第4行。目前它没有提供任何记录。我怀疑我在'in'中动态传递的temp6,查询并没有接受它。但是,temp6是“0”、“07”、“070”、“0705”、“07052”、“070526”、“0705262”、“07052620”。但不确定查询是否动态进行,可能是我在temp6中犯了一些错误。请帮助。在实际情况下,输入的数字不会是0。它最多可以是30位数字。但是,没有最小限制。谢谢,但是这个数字07052620可以是30位数字,因此在查询中,我们将在“输入”中有30个组合,请求您的输入please@VJS . . . 没关系。Oracle应该仍然使用索引。我在下面尝试了VAR_CALLING_NUM=07052620:而var1@Gordon Linoff:也添加了我尝试过的内容。请你帮忙。
WITH pred_vals AS (SELECT SUBSTR('07052620', 1, LENGTH('07052620') + 1 - LEVEL) str,
                          LEVEL priority
                   FROM   dual
                   CONNECT BY LEVEL <= LENGTH('07052620')),
     main_join AS (SELECT fi.subscriber_num,
                          fi.subscriber_status,
                          fi.p_id
                          row_number() OVER (ORDER BY pv.priority) rn
                   FROM   c_s_forward_info fi
                          INNER JOIN pred_vals pv ON (fi.subscriber_num = pv.str)
                   WHERE  scp_ver = 1)
SELECT subscriber_num,
       subscriber_status,
       p_id
FROM   main_join
WHERE  rn = 1;