Đơn giản hóa / tự động hóa dữ liệu không gian đĩa miễn phí lấy lại


8

Trên phiên bản Oracle 11g:

Sau khi Googling, tôi không thể tìm thấy một cách đơn giản để lấy lại không gian trống sau khi xóa bảng.

Tôi đã tìm thấy rất nhiều lời giải thích, cho biết làm thế nào dữ liệu bị phân mảnh, chồng các truy vấn nhàm chán mà bạn phải chạy để di chuyển "khoảng trống" ở cuối tệp dữ liệu (từng bảng ... ngay cả khi bạn Có 200 bàn !?).

Sau đó, bạn phải giảm kích thước tệp dữ liệu bằng cách "đoán" bằng cách bạn có thể giảm bao nhiêu hoặc bạn phải biết chính xác "kích thước khối" của mình là gì ... Và cuối cùng bạn không nên quên "xây dựng lại các chỉ mục".

Xem ví dụ: http://asktom.oracle.com/pls/asktom/f?p=100:11 0 ::::P11_QUESTION_ID : 54178027703899

http://www.oracle-base.com/articles/misc/ReclaimingUnuseSpace.php

Có một thủ tục PL / SQL đơn giản nào, được đặt tên không gian bảng hoặc tên tệp dữ liệu, cho công việc đó không? Hoặc bất kỳ công cụ Oracle tương tự?


Thông tin thú vị: kiểm tra xem không gian bảng của bạn là "được quản lý cục bộ" hay "quản lý thư mục". Cái trước dường như có cách xử lý tốt hơn các dữ liệu "chống phân mảnh". Xem: orafaq.com/node/3
Frosty Z

Câu trả lời:


5

Câu trả lời ngắn gọn là Không . Thật không may, cách để làm điều này trong Oracle đòi hỏi "một đống truy vấn nhàm chán". Các bài viết bạn liên kết đến là một số thông tin tốt nhất có sẵn về chủ đề này. Datafile thực sự bị phân mảnh, do đó ngay cả khi không gian trống tồn tại dưới phân khúc cao nhất, Oracle sẽ không tự động hợp nhất nó khi RESIZEhoàn thành.

Để "chống phân mảnh" vùng bảng, bạn cần di chuyển các phân đoạn này đến điểm bắt đầu của tệp dữ liệu thay vì ở cuối. Đối với các bảng, đây là một quy trình ngoại tuyến, có nghĩa là bảng sẽ không khả dụng trong khi quá trình di chuyển đang diễn ra. Các chỉ mục có thể được di chuyển ngoại tuyến hoặc với Phiên bản doanh nghiệp, chúng có thể được di chuyển trực tuyến. Vì bạn có một cửa sổ ngừng hoạt động, tôi khuyên bạn nên làm theo các bước sau.

A. Thu nhỏ các tệp dữ liệu có không gian trống vượt quá vạch nước cao. Điều này có thể được thực hiện như sau (truy vấn tương tự như quy trình của Frosty Z):

SELECT ceil( blocks*(a.BlockSize)/1024/1024) "Current Size",
   ceil( (nvl(hwm,1)*(a.BlockSize))/1024/1024 ) "Smallest Poss.",
   ceil( blocks*(a.BlockSize)/1024/1024) -
   ceil( (nvl(hwm,1)*(a.BlockSize))/1024/1024 ) "Savings",
   'alter database datafile '''|| file_name || ''' resize ' || 
      ceil((nvl(hwm,1)*(a.BlockSize))/1024/1024/100)*100  || 'm;' "Command"
FROM (SELECT a.*, p.value BlockSize FROM dba_data_files a 
JOIN v$parameter p ON p.Name='db_block_size') a
LEFT JOIN (SELECT file_id, max(block_id+blocks-1) hwm FROM dba_extents GROUP BY file_id ) b
ON a.file_id = b.file_id
WHERE ceil( blocks*(a.BlockSize)/1024/1024) - ceil( (nvl(hwm,1)*(a.BlockSize))/1024/1024 ) 
   > 100 /* Minimum MB it must shrink by to be considered. */
ORDER BY "Savings" Desc;

B. Sau khi thu nhỏ những thứ ở trên mực nước cao, hãy tìm hiểu xem không gian bảng nào vẫn có lợi khi di chuyển các phân đoạn.

SELECT DISTINCT tablespace_name FROM
(      
    SELECT tablespace_name, block_id + blocks LastBlock,
       lead(block_id) OVER (PARTITION BY File_ID 
          ORDER BY tablespace_name, file_id, block_id) NextBlock
       FROM dba_free_space 
) WHERE LastBlock <> NextBlock AND NextBlock IS NOT NULL;

C. Đối với mỗi không gian bảng này xác định phân đoạn nào cần được di chuyển. (Thay thế NGƯỜI DÙNG bằng tên của vùng bảng của bạn hoặc nối nó với truy vấn trước đó)

SELECT distinct de.segment_name
FROM dba_extents de
JOIN
(
   SELECT tablespace_name, file_id, MIN(block_id) LowestFreeBlock
   FROM dba_free_space
   WHERE tablespace_name = 'USERS'
  GROUP BY tablespace_name, file_id
) dfs ON dfs.tablespace_name = de.tablespace_name AND dfs.file_id = de.file_id
WHERE de.tablespace_name = 'USERS'
AND de.block_id > dfs.LowestFreeBlock;

D. Di chuyển từng bảng và xây dựng lại các chỉ mục và thống kê.

E. Lặp lại bước A.

Tôi chỉ xây dựng hầu hết các truy vấn này, vì vậy bạn sẽ muốn kiểm tra kỹ lưỡng trước khi sử dụng. Tôi cho rằng bạn có thể tạo một quy trình sẽ sử dụng EXECUTE IMMEDIATEđể tạo các câu lệnh thực tế để chạy một cách linh hoạt, nhưng vì các truy vấn sẽ nhận được ORA-08103: Đối tượng không còn tồn tại trong khi quá trình di chuyển đang diễn ra, tôi nghĩ tốt nhất nên kiểm soát quá trình đó theo cách thủ công nếu nó có nghĩa là thêm một chút thời gian / nỗ lực.


3

Giải pháp một phần lấy cảm hứng từ trang này :

Nó không tổ chức lại không gian trống nhưng tự động phát hiện không gian trống có sẵn ở cuối các tệp dữ liệu và in ra các lệnh 'GIẢI QUYẾT' thích hợp.

DECLARE
    BLKSIZE INTEGER;

BEGIN
    SELECT VALUE INTO BLKSIZE FROM V$PARAMETER WHERE NAME = 'db_block_size';

    FOR INDEX_ROW IN (
      SELECT 'ALTER DATABASE DATAFILE ''' || FILE_NAME || ''' RESIZE ' || CEIL( (NVL(HWM,1)*BLKSIZE)/1024/1024 ) || 'M;' SHRINK_DATAFILES FROM DBA_DATA_FILES DBADF,
            (SELECT FILE_ID, MAX(BLOCK_ID+BLOCKS-1) HWM FROM DBA_EXTENTS GROUP BY FILE_ID ) DBAFS
            WHERE DBADF.FILE_ID = DBAFS.FILE_ID(+) AND CEIL(BLOCKS*BLKSIZE/1024/1024)- CEIL((NVL(HWM,1)* BLKSIZE)/1024/1024 ) > 0
    ) LOOP
        DBMS_OUTPUT.PUT_LINE(INDEX_ROW.SHRINK_DATAFILES);
    END LOOP;
END;

2

Trước khi bạn cố gắng thu nhỏ các tệp dữ liệu, hãy tự hỏi: Bạn có định tạo lại các phân đoạn mới bên trong không gian bảng được liên kết một cách nào đó trong tương lai không xa không? Nếu có, không có điểm trong thu hẹp. Không gian sẽ chỉ được sử dụng lại cho các phân khúc mới của bạn và bạn tiết kiệm cho mình và hệ thống nhiều nỗ lực bằng cách để nó như vậy.


2

Sau khi lướt google nhiều ngày tôi đã tìm thấy ví dụ đơn giản và rõ ràng nhất để lấy lại không gian trống trong không gian bảng sau khi xóa. Tôi hi vọng cái này giúp được

Liên kết: http://www.dbforums.com/oracle/976248-how-reduce-tablespaces-use-space-after-delete-records-2.html

giải pháp:

ALTER TABLE MOVE demo

Hãy tạo một bảng có 9999 hàng trong đó, mỗi hàng có kích thước khoảng 1k:

SQL> create table t (x char(1000) default 'x' primary key);
Table created.
SQL> insert /*+ append nologging */ into t(x) select rownum from all_objects where rownum < 10000;
9999 rows created.
SQL> commit;
Commit complete.

Bảng này có 29 phạm vi được phân bổ cho nó, với tổng số 14,6M:

SQL> select count(*), sum(bytes) from user_extents where segment_name='T';
COUNT(*) SUM(BYTES)
---------- ----------
29 14680064

Hãy xóa TẤT CẢ các hàng:

SQL> delete from t;
9999 rows deleted.
SQL> commit;
Commit complete.

Bây giờ- "bất ngờ" - bảng vẫn sử dụng cùng mức độ:

SQL> select count(*), sum(bytes) from user_extents where segment_name='T';
COUNT(*) SUM(BYTES)
---------- ----------
29 14680064

Tại sao ? Bởi vì ngay cả khi bạn xóa tất cả các hàng của bảng, High Water Mark vẫn không bị giảm - nó không bao giờ giảm, để cho phép đồng thời tối đa (Oracle rất nghiêm túc về việc tối đa hóa đồng thời tức là hiệu suất và khả năng mở rộng; đó là lý do chính đằng sau thành công của nó trong các ứng dụng Doanh nghiệp).

Việc sắp xếp lại không gian chưa sử dụng (= không gian phía trên CTM) không giúp ích nhiều (vì không có nhiều không gian chưa sử dụng phía trên CTM):

SQL> alter table t deallocate unused;
Table altered.
SQL> select count(*), sum(bytes) from user_extents where segment_name='T';
COUNT(*) SUM(BYTES)
---------- ----------
29 13959168

Bây giờ, hãy M CHUYỂN bảng, về bản chất có nghĩa là sao chép bảng (bao gồm cả kích hoạt, ràng buộc, v.v.), chuyển các hàng, thả bảng "cũ" và đổi tên mới - tất cả được tạo bởi kernel, vì vậy siêu an toàn ngay cả trong trường hợp máy / máy chủ bị lỗi:

SQL> alter table t move;
Table altered.

Bây giờ, chúng ta chỉ có phạm vi ban đầu được phân bổ:

SQL> select count(*), sum(bytes) from user_extents where segment_name='T';
COUNT(*) SUM(BYTES)
---------- ----------
1 65536

Hãy cẩn thận: thông thường xảy ra rằng nhiều / tất cả các chỉ mục trên bảng là KHÔNG THỂ sau khi di chuyển (không phải trong trường hợp này nhưng tôi đang chạy 9.2.0.4, phiên bản mới nhất, có thể đã tối ưu hóa quy trình trong trường hợp các bảng hoàn toàn trống ):

SQL> col table_name form a30
SQL> col index_name form a30
SQL> set lines 123 
SQL> select table_name, index_name, status from user_indexes where table_name='T';

TABLE_NAME INDEX_NAME STATUS
------------------------------ ------------------------------ ------------------------
T SYS_C002573 VALID

Nếu TÌNH TRẠNG không có giá trị, bạn có thể chỉ cần xây dựng lại thủ công (các) chỉ mục:

SQL> alter index SYS_C002573 rebuild;
Index altered.

Hoặc bạn có thể tự động hóa toàn bộ quá trình:

set serveroutput on size 100000
begin
for n in (select index_name from user_indexes where status <> 'VALID') loop
dbms_output.put_line ('rebuilding ' || n.index_name);
execute immediate 'alter index ' || n.index_name || ' rebuild';
end loop;
end;
/

Ví dụ: hãy đặt thủ công chỉ mục thành UNUSABLE:

SQL> alter index SYS_C002573 unusable;
Index altered.

SQL> set serveroutput on size 100000
SQL> begin
2 for n in (select index_name from user_indexes where status <> 'VALID') loop
3 dbms_output.put_line ('rebuilding ' || n.index_name);
4 execute immediate 'alter index ' || n.index_name || ' rebuild';
5 end loop;
6 end;
7 /
rebuilding SYS_C002573

PL/SQL procedure successfully completed.

HTH


1

Như đã nói trước đó, bạn sẽ phải di chuyển tất cả hơn 200 bảng trong không gian bảng đó để giải phóng một số không gian trong kho dữ liệu của bạn và sau đó thay đổi kích thước để lấy lại không gian. Nhưng thay vì chạy tất cả các truy vấn đó, người quản lý Doanh nghiệp 12c thực hiện nhiệm vụ này. Bạn sẽ phải điều hướng đến Cơ sở dữ liệu Trang chủ> Lưu trữ> Không gian bảng. Chọn không gian bảng bạn muốn làm việc và bấm Sắp xếp lại. Nó sẽ đưa ra một tùy chọn để xem các câu lệnh SQL sắp được thực thi. Bạn có thể lấy một bản sao của chúng và tự chạy nó hoặc lên lịch cho một công việc trong EM.

Nó thực sự tạo ra một không gian bảng khác, di chuyển tất cả các đối tượng sang không gian bảng mới, xây dựng lại các chỉ mục và thả các đối tượng từ không gian bảng cũ.

Có một vài nhược điểm tôi có thể nghĩ ra. Điều này nên được thực hiện trong giờ thấp điểm nếu không nó sẽ báo lỗi tài nguyên đang bận. Tệp dữ liệu (không phải vùng bảng) sẽ có "reorg" được thêm vào tên của nó, cho đến cuối.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.