🔥 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