Chủ Nhật, 8 tháng 11, 2026

ORA-01555: SNAPSHOT TOO OLD – Giải thích theo phương pháp Feynman

🔥 ORA-01555: SNAPSHOT TOO OLD – Giải thích theo phương pháp Feynman

Tại sao Oracle Database chạy báo cáo gần 2 giờ, đến phút 119 mới báo lỗi, dù UNDO Tablespace vẫn còn dung lượng?

Để hiểu tận gốc lỗi ORA-01555, chúng ta sẽ áp dụng phương pháp Feynman Technique: biến một cơ chế Oracle phức tạp thành câu chuyện đời thường, sau đó mới đi vào kiến trúc, SQL và cách xử lý thực tế.

1. 🧠 Hiểu ORA-01555 trong 30 giây

Hãy tưởng tượng:

  • 📖 Bạn đang đọc một cuốn sổ kế toán có 1 triệu dòng.
  • ✍️ Trong lúc bạn đọc, kế toán vẫn liên tục sửa số liệu.
  • 📸 Bạn yêu cầu: “Tôi muốn xem toàn bộ số liệu đúng như lúc 8 giờ sáng, không lấy những thay đổi sau đó.”
  • 🗃️ Kế toán có một kho lưu các phiên bản cũ của những trang sổ đã sửa.
  • ⏳ Đến gần cuối cuốn sổ, bạn cần xem lại một trang theo phiên bản 8 giờ, nhưng bản cũ đã bị dọn đi để lấy chỗ lưu phiên bản khác.

Kết quả: Bạn không thể hoàn thành báo cáo vì không còn đủ dữ liệu lịch sử để tái dựng trang sổ tại thời điểm ban đầu.

Đó chính là bản chất phổ biến nhất của ORA-01555.

Minh họa một tình huống ORA-01555 do mất thông tin UNDO cần thiết.

Điểm quan trọng: ORA-01555 không đơn thuần là thiếu dung lượng hay thiếu thời gian. Nó xảy ra khi Oracle không còn truy cập được thông tin UNDO cần thiết để duy trì tính nhất quán của dữ liệu.

2. 📚 Oracle đọc dữ liệu như thế nào?

Oracle có hai cách đọc dữ liệu quan trọng:

Khái niệm

Giải thích bình dân

Current Read

Đọc phiên bản hiện tại của block để thực hiện thao tác phù hợp

Consistent Read

Đọc phiên bản dữ liệu phù hợp với thời điểm nhất quán của câu SQL

SCN

Con số Oracle dùng để xác định thứ tự logic của các thay đổi

UNDO

Thông tin giúp hoàn tác thay đổi và dựng lại phiên bản cũ

ORA-01555

Oracle không dựng được phiên bản cũ cần thiết

Ví dụ: Tài khoản ngân hàng

Giả sử bảng ACCOUNTS có dữ liệu:

Thời điểm

Số dư tài khoản A

08:00

100 triệu

08:30

80 triệu

09:00

50 triệu

09:30

120 triệu

Một báo cáo bắt đầu lúc 08:00 cần xem số dư của tài khoản A tại thời điểm đó.

Dù đến 09:30 số dư đã là 120 triệu, báo cáo vẫn phải nhìn thấy 100 triệu, nếu đây là phiên bản đúng với snapshot của câu truy vấn.

Oracle dùng UNDO để dựng lại phiên bản 100 triệu, thay vì bắt báo cáo đọc giá trị mới.

Đó là cơ chế Read Consistency.

3. 🔬 Điều gì thực sự diễn ra bên trong Oracle?

Hãy xem sơ đồ sau. Một câu SELECT bắt đầu tại SCN 1000, trong khi các transaction khác liên tục UPDATE dữ liệu.

Diễn biến theo từng bước

Bước 1 – 08:00: Báo cáo chạy:

SELECT SUM(balance)

FROM accounts;

Giả sử Oracle xác định snapshot SCN = 1000.

Bước 2 – 08:30: Giao dịch khác UPDATE tài khoản A từ 100 triệu xuống 80 triệu rồi COMMIT.

Oracle ghi thông tin UNDO cần thiết để có thể khôi phục phiên bản trước khi sửa.

Bước 3 – 09:00: Một giao dịch tiếp tục UPDATE từ 80 triệu xuống 50 triệu rồi COMMIT.

Bước 4 – 09:59: Báo cáo đến block chứa tài khoản A. Block hiện tại là 50 triệu, nhưng báo cáo cần 100 triệu.

Oracle phải sử dụng chuỗi UNDO để quay ngược:

50 triệu

Hiện tại

80 triệu

UNDO 2

100 triệu

UNDO 1

Quá trình tái dựng phiên bản cũ (minh họa đơn giản hóa).

Nếu UNDO 1 đã bị ghi đè, Oracle không thể quay về giá trị 100 triệu. Câu SELECT có thể thất bại với ORA-01555.

Vì sao phút 118 vẫn chạy, phút 119 mới chết?

Vì Oracle không kiểm tra toàn bộ các phiên bản cũ ngay khi câu SQL bắt đầu.

Oracle đọc và xử lý các block trong quá trình thực thi. Đến khi gặp một block cần thông tin UNDO đã mất, lỗi mới xuất hiện.

Vì thế một câu SQL chạy 5 phút hay 5 giờ đều có thể gặp ORA-01555. Không tồn tại quy tắc Oracle luôn báo lỗi khi thời gian chạy vượt UNDO_RETENTION.

4. ⏳ UNDO_RETENTION là gì? Ví dụ bằng chiếc tủ hồ sơ

Hãy tưởng tượng UNDO Tablespace là một chiếc tủ có sức chứa hữu hạn, còn UNDO_RETENTION là thời gian Oracle cố gắng giữ hồ sơ cũ trước khi cho phép tái sử dụng chỗ.

  • UNDO_RETENTION = 900: Mục tiêu giữ UNDO đã commit khoảng 15 phút.
  • UNDO_RETENTION = 7200: Mục tiêu giữ khoảng 2 giờ.
  • UNDO_RETENTION = 10800: Mục tiêu giữ khoảng 3 giờ.

Nhưng có một điều DBA cần đặc biệt hiểu: UNDO_RETENTION không phải lúc nào cũng là cam kết giữ dữ liệu đủ thời gian.

Trong chế độ NOGUARANTEE, khi thiếu không gian UNDO, Oracle có thể tái sử dụng UNDO đã hết hiệu lực với transaction, kể cả khi chưa đạt retention mong muốn.

Ngược lại, RETENTION GUARANTEE ưu tiên bảo vệ UNDO chưa hết thời gian retention, nhưng có thể khiến DML lỗi ORA-30036 khi hết chỗ.

Mô phỏng tương tác: Tại sao tăng UNDO_RETENTION chưa chắc hết lỗi?

Thử thay đổi 3 tham số

Mô phỏng

Thời gian chạy query

120 phút

UNDO_RETENTION mục tiêu

180 phút

UNDO capacity khả dụng (giả định)

80 GiB

UNDO cần ước tính

98.9 GiB

Chênh lệch dung lượng

-18.9 GiB

Chưa đạt điều kiện định cỡ sơ bộ

Dung lượng chưa đủ cho mức sinh UNDO giả định.

Mô hình đơn giản với tốc độ sinh 1.200 undo block/giây, block size 8 KiB, không tính các overhead và không bảo đảm ngăn được ORA-01555.

Chỉ cần tăng tốc độ UPDATE hoặc giảm dung lượng UNDO, thời gian giữ phiên bản cũ trên thực tế có thể giảm mạnh.

5. 🔎 Tại sao tăng UNDO Tablespace rồi vẫn ORA-01555?

Không phải mọi ORA-01555 đều xuất phát từ UNDO quá nhỏ.

Nguyên nhân

Ví dụ thực tế

Cách khắc phục

⏳ UNDO bị ghi đè

Query 2 giờ, DML tạo nhiều UNDO

Tăng retention và định cỡ UNDO

🐢 Query quá chậm

Full table scan, thiếu partition pruning

SQL tuning, tối ưu execution plan

🔄 Fetch across commit

Cursor đọc dữ liệu, đồng thời UPDATE/COMMIT

Thiết kế lại batch

🧩 LOB retention

Đọc phiên bản cũ của LOB nhưng dữ liệu lịch sử không còn

Kiểm tra loại LOB và cơ chế retention

⚙️ Delayed block cleanout

Oracle cần thông tin transaction cũ nhưng UNDO liên quan không còn

Kiểm tra tình trạng cleanout và transaction history

Ví dụ nguy hiểm: Fetch across commit

Giả sử bạn có 1 triệu khách hàng cần cập nhật trạng thái.

DECLARE

  CURSOR c IS

    SELECT id FROM customers;

BEGIN

  FOR r IN c LOOP

    UPDATE customers

    SET status = 'ACTIVE'

    WHERE id = r.id;


    COMMIT;

  END LOOP;

END;

/

Vấn đề là cursor đang đọc bảng CUSTOMERS, trong khi chính chương trình liên tục thay đổi và COMMIT dữ liệu trên bảng đó.

Cursor vẫn cần duy trì snapshot nhất quán. Việc COMMIT liên tục có thể tạo điều kiện để UNDO cần cho cursor bị tái sử dụng, gây ORA-01555. Tuy nhiên, không phải cứ COMMIT trong vòng lặp là chắc chắn xảy ra lỗi.

Cách làm tốt hơn: Chia thành các batch theo khóa ổn định, mỗi batch thực hiện một câu UPDATE riêng, COMMIT sau khi hoàn thành batch. Nếu cần snapshot cố định xuyên suốt toàn bộ quá trình, phải thiết kế riêng cơ chế bảo đảm tính nhất quán.

6. 🛠️ Runbook kiểm tra ORA-01555 trên Oracle 11g/19c

Bước 1. Kiểm tra cấu hình UNDO

SHOW PARAMETER undo;


SELECT tablespace_name,

       retention

FROM dba_tablespaces

WHERE contents = 'UNDO';


SELECT tablespace_name,

       ROUND(SUM(bytes)/1024/1024/1024,2) size_gb

FROM dba_data_files

WHERE tablespace_name IN (

  SELECT tablespace_name

  FROM dba_tablespaces

  WHERE contents = 'UNDO'

)

GROUP BY tablespace_name;

Với Oracle RAC, cần kiểm tra UNDO Tablespace và các tham số liên quan theo từng instance.

Bước 2. Xem lịch sử UNDO

SELECT begin_time,

       end_time,

       maxquerylen,

       maxqueryid,

       undoblks,

       tuned_undoretention,

       ssolderrcnt,

       nospaceerrcnt,

       unxpstealcnt,

       unxpblkrelcnt

FROM v$undostat

ORDER BY begin_time DESC;

Các chỉ số quan trọng:

  • MAXQUERYLEN: Thời gian query dài nhất ghi nhận trong khoảng thống kê, tính bằng giây.
  • TUNED_UNDORETENTION: Thời gian retention Oracle tự điều chỉnh.
  • SSOLDERRCNT: Số lần ghi nhận lỗi snapshot too old.
  • NOSPACEERRCNT: Số lần thiếu không gian UNDO.
  • UNXPSTEALCNT: Số lần Oracle cố gắng lấy extent UNDO chưa hết hạn để tái sử dụng.

Lưu ý: V$UNDOSTAT lưu các khoảng thống kê khoảng 10 phút và thường có tối đa 576 bản ghi, tương đương khoảng 4 ngày. Muốn phân tích một tuần hoặc nhiều tháng, cần có lịch sử thu thập riêng hoặc nguồn dữ liệu lịch sử phù hợp.

Bước 3. Tính tốc độ sinh UNDO

SELECT begin_time,

       end_time,

       undoblks,

       ROUND(undoblks / 600, 2) undo_blocks_sec

FROM v$undostat

ORDER BY begin_time DESC;

Công thức trên giả định mỗi khoảng thống kê là 600 giây; để chính xác hơn nên tính từ END_TIME - BEGIN_TIME.

Ví dụ:

  • Query dài nhất: 7.200 giây.
  • Dự phòng 20%: 8.640 giây.
  • Peak UPS: 1.200 block/giây.
  • DB block size: 8 KiB.

UNDO = 8640 \times 1200 \times 8192

Kết quả khoảng 79,1 GiB, tương đương 84,9 GB theo hệ thập phân.

Đây là mức ước tính để lập kế hoạch capacity, không phải dung lượng bảo đảm hết lỗi. Cần tính thêm mức sử dụng thực tế, biến động tải, extent overhead và tăng trưởng.

Bước 4. Kiểm tra lỗi thực tế theo thời gian

SELECT begin_time,

       ssolderrcnt,

       nospaceerrcnt,

       maxquerylen,

       tuned_undoretention

FROM v$undostat

WHERE ssolderrcnt > 0

   OR nospaceerrcnt > 0

ORDER BY begin_time DESC;

Tìm SQL liên quan trong application log, trace file và ADR. Một số trace có thể chứa thông tin query duration, SQL hoặc SCN, nhưng không nên mặc định alert log luôn có SQL_ID và Query Duration.

Bước 5. Điều chỉnh có kiểm soát

Ví dụ đặt mục tiêu retention 3 giờ:

ALTER SYSTEM SET undo_retention = 10800

SCOPE=BOTH;

Trước khi thực hiện cần kiểm tra UNDO capacity, autoextend, maxsize, disk/ASM free space và chính sách RETENTION GUARANTEE.

Đặc biệt với RAC 11g/19c, không thay đổi đồng loạt trên Production khi chưa đánh giá tác động đến từng instance và workload.

7. 🎯 Ba điều cần nhớ theo Feynman

SCN giống như mốc chụp ảnh

Câu SQL cần nhìn dữ liệu nhất quán tại một mốc logic, dù các transaction khác vẫn cập nhật.

UNDO giống như kho lưu lịch sử chỉnh sửa

Oracle dùng lịch sử thay đổi để dựng lại phiên bản dữ liệu phù hợp với snapshot.

ORA-01555 giống như mất một trang lịch sử quan trọng

Khi Oracle cần phiên bản cũ nhưng không còn đủ thông tin để dựng lại, câu SQL có thể thất bại.

Một điểm cần chỉnh trong bài viết gốc

Câu “ORA-01555 không phải lỗi thiếu chỗ, mà là lỗi thiếu thời gian” rất dễ nhớ nhưng chưa hoàn toàn chính xác về kỹ thuật.

Nên diễn đạt:

ORA-01555 là lỗi Oracle không còn đủ thông tin UNDO để tái dựng dữ liệu nhất quán tại snapshot cần đọc. Nguyên nhân thường liên quan đến thời gian chạy query, tốc độ phát sinh UNDO và khả năng lưu giữ UNDO; đôi khi còn do thiết kế batch, LOB hoặc delayed block cleanout.

Và nguyên tắc vận hành Production là: giảm thời gian query, kiểm soát tốc độ sinh UNDO, định cỡ retention và dung lượng bằng số liệu thực tế, đồng thời giám sát SSOLDERRCNT.

Đối với các hệ thống Oracle RAC xử lý giao dịch 24/7 như CCBS, Billing hoặc các batch đối soát cuối tháng, nên giám sát riêng UNDO theo từng instance và theo khung giờ cao điểm. Đây là cách phát hiện rủi ro trước khi một báo cáo chạy 119 phút rồi thất bại.



=============================
TƯ VẤN: Click Here hoặc Hotline/Zalo 090.29.12.888
=============================
Website không chứa bất kỳ quảng cáo nào, mọi đóng góp để duy trì phát triển cho website (donation) xin vui lòng gửi về STK 90.2142.8888 - Ngân hàng Vietcombank Thăng Long - TRAN VAN BINH
=============================
Nếu bạn không muốn bị AI thay thế và tiết kiệm 3-5 NĂM trên con đường trở thành DBA chuyên nghiệp hay làm chủ Database thì hãy đăng ký ngay KHOÁ HỌC ORACLE DATABASE A-Z ENTERPRISE, được Coaching trực tiếp từ tôi với toàn bộ bí kíp thực chiến, thủ tục, quy trình của gần 20 năm kinh nghiệm (mà bạn sẽ KHÔNG THỂ tìm kiếm trên Internet/Google) từ đó giúp bạn dễ dàng quản trị mọi hệ thống Core tại Việt Nam và trên thế giới, đỗ OCP.
- CÁCH ĐĂNG KÝ: Gõ (.) hoặc để lại số điện thoại hoặc inbox https://m.me/tranvanbinh.vn hoặc Hotline/Zalo 090.29.12.888
- Chi tiết tham khảo:
https://bit.ly/oaz_w
=============================
2 khóa học online qua video giúp bạn nhanh chóng có những kiến thức nền tảng về Linux, Oracle, học mọi nơi, chỉ cần có Internet/4G:
- Oracle cơ bản: https://bit.ly/admin_1200
- Linux: https://bit.ly/linux_1200
=============================
KẾT NỐI VỚI CHUYÊN GIA TRẦN VĂN BÌNH:
📧 Mail: binhoracle@gmail.com
☎️ Mobile/Zalo: 0902912888
👨 Facebook: https://www.facebook.com/BinhOracleMaster
👨 Inbox Messenger: https://m.me/101036604657441 (profile)
👨 Fanpage: https://www.facebook.com/tranvanbinh.vn
👨 Inbox Fanpage: https://m.me/tranvanbinh.vn
👨👩 Group FB: https://www.facebook.com/groups/DBAVietNam
👨 Website: https://www.tranvanbinh.vn
👨 Blogger: https://tranvanbinhmaster.blogspot.com
🎬 Youtube: https://www.youtube.com/@binhguru
👨 Tiktok: https://www.tiktok.com/@binhguru
👨 Linkin: https://www.linkedin.com/in/binhoracle
👨 Twitter: https://twitter.com/binhguru
👨 Podcast: https://www.podbean.com/pu/pbblog-eskre-5f82d6
👨 Địa chỉ: Tòa nhà Sun Square - 21 Lê Đức Thọ - Phường Mỹ Đình 1 - Quận Nam Từ Liêm - TP.Hà Nội

=============================
cơ sở dữ liệu, cơ sở dữ liệu quốc gia, database, AI, trí tuệ nhân tạo, artificial intelligence, machine learning, deep learning, LLM, ChatGPT, DeepSeek, Grok, oracle tutorial, học oracle database, Tự học Oracle, Tài liệu Oracle 12c tiếng Việt, Hướng dẫn sử dụng Oracle Database, Oracle SQL cơ bản, Oracle SQL là gì, Khóa học Oracle Hà Nội, Học chứng chỉ Oracle ở đầu, Khóa học Oracle online,sql tutorial, khóa học pl/sql tutorial, học dba, học dba ở việt nam, khóa học dba, khóa học dba sql, tài liệu học dba oracle, Khóa học Oracle online, học oracle sql, học oracle ở đâu tphcm, học oracle bắt đầu từ đâu, học oracle ở hà nội, oracle database tutorial, oracle database 12c, oracle database là gì, oracle database 11g, oracle download, oracle database 19c/21c/23c/23ai, oracle dba tutorial, oracle tunning, sql tunning , oracle 12c, oracle multitenant, Container Databases (CDB), Pluggable Databases (PDB), oracle cloud, oracle security, oracle fga, audit_trail,oracle RAC, ASM, oracle dataguard, oracle goldengate, mview, oracle exadata, oracle oca, oracle ocp, oracle ocm , oracle weblogic, postgresql tutorial, mysql tutorial, mariadb tutorial, ms sql server tutorial, nosql, mongodb tutorial, oci, cloud, middleware tutorial, docker, k8s, micro service, hoc solaris tutorial, hoc linux tutorial, hoc aix tutorial, unix tutorial, securecrt, xshell, mobaxterm, putty

ĐỌC NHIỀU

Trần Văn Bình - Oracle Database Master