oracle—使用not in sql查询时,优化此sql语句的最佳方法是什么?

8gsdolmq  于 2021-07-29  发布在  Java
关注(0)|答案(2)|浏览(583)

那张table叫 TB_ORDER 有9000万条数据记录,但只有500条状态既不是b也不是c的记录。

SELECT 
    ORDER.ID,ORDER.STATE,ORDER.NAME 
FROM 
    TB_ORDER ORDER 
WHERE 
    ORDER.STATE NOT IN ('B','C') ;

我的同事这样写sql,因为 full table scan 。所以我试着这样修改它。可以吗?我在状态字段上添加了索引。它还在吗 full table scan 因为子查询sql结果非常大((90000000-500)/90000000)?

SELECT 
    A.ID,A.NAME,A.STATE 
FROM TB_ORDER A 
WHERE 
    NOT EXISTS
        (
        SELECT 1 FROM TB_ORDER B WHERE A.ID=B.ID and B.STATE='B'
        UNION ALL
        SELECT 1 FROM TB_ORDER C WHERE A.ID=C.ID and C.STATE='C'
        )
pprl5pva

pprl5pva1#

你真的需要那个不在里面的人吗?您可以通过使用函数然后创建基于函数的索引来解决这个问题。确保where子句与 predicate 完全匹配。例子:

-- table
create table t_large_table (id NUMBER GENERATED ALWAYS AS IDENTITY,state VARCHAR2(1));
-- some sample data
DECLARE
BEGIN
  FOR i IN 1 .. 10 LOOP
    INSERT INTO t_large_table (state) VALUES ('A');
    INSERT INTO t_large_table (state) VALUES ('B');
  END LOOP;
  INSERT INTO t_large_table (state) VALUES ('C');
  INSERT INTO t_large_table (state) VALUES ('D');
  COMMIT;
END;
/

-- create index with function that has a bucket to put all states that are relevant to me. In this case everything that is not A or B
CREATE INDEX t_large_table_idx 
  ON t_large_table (CASE state WHEN 'A' THEN 'A' WHEN 'B' THEN 'B' ELSE 'X' END);

-- run a select with exactly same function as the index
SELECT * 
  FROM t_large_table
 WHERE CASE state WHEN 'A' THEN 'A' WHEN 'B' THEN 'B' ELSE 'X' END = 'X';

-- check explain plan
-----------------------------------------------------------------
| Id  | Operation                           | Name              |
-----------------------------------------------------------------
|   0 | SELECT STATEMENT                    |                   |
|   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| T_LARGE_TABLE     |
|   2 |   INDEX RANGE SCAN                  | T_LARGE_TABLE_IDX |
-----------------------------------------------------------------
wko9yo5t

wko9yo5t2#

我给你提个建议,你可以试试。

Select o.ID,o.o,o.NAME 
FROM TB_ORDER o
Inner Join
(
 Select STATE  from
 (
  Select STATE from TB_ORDER Group by ORDER 
 ) Q Where STATE NOT IN ('B','C') 
) QQ on QQ.STATE = o.STATE

相关问题