Oracle
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Oracle

Nhận 10 số manual_sequence chưa sử dụng đầu tiên

Đầu tiên Tôi sẽ thay thế truy vấn con phức tạp này:

Select Rownum seq_number From Dual Connect By Rownum <= 
         (Select LPAD(9,(UTC.DATA_PRECISION - UTC.DATA_SCALE),9) 
          From User_Tab_Columns UTC 
          where UTC.Table_Name = 'Table_Name' And UTC.Column_Name = 'seq_number')

với cái này:

Select Rownum As seq_number From Dual 
Connect By Rownum <= (Select max( seq_number ) + 10 From TEMP_TABLE_NAME ) 

hoặc thậm chí với một hằng số đơn giản:

Select Rownum As seq_number From Dual Connect By Rownum <= 1000000

Thực sự thì truy vấn con của bạn không hoạt động đối với trường hợp rất cơ bản:

create table TEMP_TABLE_NAME(
  seq_number NUMBER
);

SELECT LPAD (9,(UTC.DATA_PRECISION - UTC.DATA_SCALE),9) as x , 
       UTC.DATA_PRECISION, UTC.DATA_SCALE, UTC.COLUMN_NAME
FROM User_Tab_Columns UTC
WHERE     UTC.Table_Name = 'TEMP_TABLE_NAME'
  AND UTC.Column_Name = 'SEQ_NUMBER'
;

X        DATA_PRECISION DATA_SCALE COLUMN_NAME
-------- -------------- ---------- -----------
  (null)         (null)     (null) SEQ_NUMBER

Và trường hợp thứ hai:

create table TEMP_TABLE_NAME(
  seq_number NUMBER(15,0)
);

trong trường hợp này, truy vấn con cố gắng tạo 999999999999999 hàng, điều này nhanh chóng dẫn đến lỗi hết bộ nhớ

SELECT count(*) FROM (
 SELECT ROWNUM seq_number
              FROM DUAL
        CONNECT BY ROWNUM <=
                      (SELECT LPAD (9,(UTC.DATA_PRECISION - UTC.DATA_SCALE),9)
                         FROM User_Tab_Columns UTC
                        WHERE     UTC.Table_Name = 'TEMP_TABLE_NAME'
                              AND UTC.Column_Name = 'SEQ_NUMBER')
);

ORA-30009: Not enough memory for CONNECT BY operation
30009. 0000 -  "Not enough memory for %s operation"
*Cause:    The memory size was not sufficient to process all the levels of the
           hierarchy specified by the query.
*Action:   In WORKAREA_SIZE_POLICY=AUTO mode, set PGA_AGGREGATE_TARGET to
           a reasonably larger value.
           Or, in WORKAREA_SIZE_POLICY=MANUAL mode, set SORT_AREA_SIZE to a
           reasonably larger value.

Thứ hai, truy vấn của bạn không mang tính xác định !!!
Nó phụ thuộc mạnh mẽ vào cấu trúc bảng vật lý và không áp đặt thứ tự chính xác bằng cách sử dụng ORDER BY mệnh đề.
Hãy nhớ -> Wikipedia - ĐẶT HÀNG THEO

Hãy xem xét trường hợp thử nghiệm này:

create table TEMP_TABLE_NAME 
as SELECT * FROM (
    select rownum as seq_number , t.*
    from ALL_OBJECTS t
    cross join ( select * from dual connect by level <= 10)
    where rownum <= 100000
)
ORDER BY DBMS_RANDOM.Value;
create unique index TEMP_TABLE_NAME_IDX on TEMP_TABLE_NAME(seq_Number);

select count(*) from TEMP_TABLE_NAME;
  COUNT(*)
----------
    100000

DELETE FROM TEMP_TABLE_NAME
WHERE seq_number between 10000 and 10002
  OR seq_number between 20000 and 20002
  OR seq_number between 30000 and 30002
  OR seq_number between 40000 and 40002
  OR seq_number between 50000 and 50002
  OR seq_number between 60000 and 60002
  ;

Nếu chỉ mục tồn tại, thì kết quả là OK:

SELECT T1.*
  FROM (    SELECT ROWNUM seq_number
              FROM DUAL
        CONNECT BY ROWNUM <= 1000000
) T1,
       TEMP_TABLE_NAME T2
 WHERE     T1.seq_number = T2.seq_number(+)
       AND T2.ROWID IS NULL
       AND ROWNUM <= 10
;

SEQ_NUMBER
----------
     10000
     10001
     10002
     20000
     20001
     20002
     30000
     30001
     30002
     40000

Nhưng điều gì sẽ xảy ra khi một ngày nào đó ai đó xóa chỉ mục hoặc trình tối ưu hóa vì một số lý do quyết định không sử dụng chỉ mục đó?
Theo định nghĩa: Không có ORDER BY, hệ thống cơ sở dữ liệu quan hệ có thể trả về các hàng trong bất kỳ đặt hàng. Tôi mô phỏng những trường hợp này bằng cách sử dụng gợi ý:

SELECT /*+ NO_INDEX(T2) */ T1.*
  FROM (    SELECT ROWNUM seq_number
              FROM DUAL
        CONNECT BY ROWNUM <= 1000000
) T1,
       TEMP_TABLE_NAME T2
 WHERE     T1.seq_number = T2.seq_number(+)
       AND T2.ROWID IS NULL
       AND ROWNUM <= 10
;

SEQ_NUMBER
----------
    213856
    910281
    668862
    412743
    295487
    214762
    788486
    346216
    777734
    806457

Truy vấn dưới đây thực thi một thứ tự thích hợp bằng cách sử dụng ORDER BY mệnh đề và cung cấp kết quả tái tạo bất kể chỉ mục phù hợp có tồn tại hay không.
Tôi đang sử dụng mệnh đề ANSI SQL LEFT JOIN được khuyến nghị thay vì đã lỗi thời WHERE .... (+) cú pháp.

SELECT  * FROM (
    SELECT /*+ NO_INDEX(T2) */ T1.*
      FROM (    SELECT ROWNUM seq_number
                  FROM DUAL
            CONNECT BY ROWNUM <= 1000000
    ) T1 
    LEFT JOIN TEMP_TABLE_NAME T2
    ON T1.seq_number = T2.seq_number
    WHERE T2.ROWID IS NULL
    ORDER BY T1.seq_number
)
WHERE ROWNUM <= 10

Hiệu suất
Cách dễ nhất để kiểm tra hiệu suất là thực hiện kiểm tra - chạy truy vấn từ 10 đến 100 lần và đo thời gian:

SET TIMING ON;
DECLARE
   x NUMBER;
BEGIN
   FOR i IN 1..10 LOOP
      SELECT sum( seq_number ) INTO x
      FROM (
           SELECT  * FROM (
            SELECT T1.*
              FROM (    SELECT ROWNUM seq_number
                          FROM DUAL
                    CONNECT BY ROWNUM <= 1000000
            ) T1 
            LEFT JOIN TEMP_TABLE_NAME T2
            ON T1.seq_number = T2.seq_number
            WHERE T2.ROWID IS NULL
            ORDER BY T1.seq_number
            )
            WHERE ROWNUM <= 10
        );
    END LOOP;
END;
/

PL/SQL procedure successfully completed.

Elapsed: 00:00:11.750

10 lần - 11,75 giây, vì vậy một truy vấn mất 1,2 giây.

Và một phiên bản tiếp theo có giới hạn trong CONNECT BY sử dụng truy vấn con:

SET TIMING ON;
DECLARE
   x NUMBER;
BEGIN
   FOR i IN 1..10 LOOP
      SELECT sum( seq_number ) INTO x
      FROM (
           SELECT  * FROM (
            SELECT T1.*
              FROM (    SELECT ROWNUM seq_number
                          FROM DUAL
                    CONNECT BY ROWNUM <= (Select max( seq_number ) + 10 From TEMP_TABLE_NAME ) 
            ) T1 
            LEFT JOIN TEMP_TABLE_NAME T2
            ON T1.seq_number = T2.seq_number
            WHERE T2.ROWID IS NULL
            ORDER BY T1.seq_number
            )
            WHERE ROWNUM <= 10
        );
    END LOOP;
END;
/
PL/SQL procedure successfully completed.

Elapsed: 00:00:00.986

Tốt hơn nhiều - chỉ 100 mili giây.
Điều này dẫn đến kết luận rằng CONNECT BY phần tốn kém nhất.

Một nỗ lực khác sử dụng bảng có dãy số được tạo trước lên đến 1 triệu (loại chế độ xem cụ thể hóa) thay vì CONNECT BY truy vấn con tạo ra các số mỗi khi di chuyển trong bộ nhớ:

create table seq(
   seq_number int primary key
)
ORGANIZATION INDEX ;

INSERT INTO seq 
SELECT level FROM dual
CONNECT BY LEVEL <= 1000000;

SET TIMING ON;
DECLARE
   x NUMBER;
BEGIN
   FOR i IN 1..10 LOOP
      SELECT sum( seq_number ) INTO x
      FROM (
           SELECT  * FROM (
            SELECT T1.*
            FROM seq T1 
            LEFT JOIN TEMP_TABLE_NAME T2
            ON T1.seq_number = T2.seq_number
            WHERE T2.ROWID IS NULL
            ORDER BY T1.seq_number
            )
            WHERE ROWNUM <= 10
        );
    END LOOP;
END;
/

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.398

Cái này nhanh nhất - chỉ 40 mili giây

cái đầu tiên 1200 mili giây, cái cuối cùng 40 mili giây - nhanh hơn 30 lần (3000%).




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. oracle làm thế nào để thay đổi bảng thêm phân vùng theo khoảng thời gian

  2. Khả năng tương thích với phiên bản Oracle Client và ODP.NET

  3. Docker Oracle Instant Client

  4. Oracle - xóa các bản sao

  5. Tích lũy thêm dữ liệu còn thiếu từ tháng trước hoặc năm trước