Archive Log tràn ổ cứng gây dừng Database Oracle

Archived Log Mode là một chế độ của Orace phục vụ việc backup database. Archiver Process chính là process chịu trách nhiệm ghi log file ra file archive để lưu trữ. Ta có thể sử dụng các archive log này để tiến hành restore dữ liệu. Archiver Process chỉ chạy khi database đang được cấu hình chế độ chạy Archived Log Mode.

Hôm vừa hệ thống bên mình gặp tình trạng Database bị stop không rõ nguyên nhân. Qua kiểm tra một hồi thì phát hiện ổ cứng bị đầy do Archived Log sinh ra quá nhiều. Việc Archived Log bị tràn sẽ làm Archiver Process bị lỗi không thể chạy dẫn đến các thao tác mà Database không làm được nên treo cả hệ thống.

Archived Log Mode on Oracle

Sự cố này khá là nghiêm trọng vì nó gây dừng Database. Các hoạt động thực hiện đến nó không thể thực hiện được. Hiện tượng Archived Log bị tràn thỉnh thoảng mới xảy xa nhưng lần này nó phát sinh tới 100GB Archived Log thì đúng là bất thường.

Nguyên nhân gây nên tình trạng này là do 1 job hàng ngày tiến hành xóa và insert một lượng lớn dữ liệu nên Archived Log phát sinh ngày càng nhiều. Vì Archived Log có nhiệm vụ ghi lại toàn bộ sự thay đổi của table nên hàng ngày nó vẫn lưu trữ các thông tin này lại. Mặc dù thực tế dữ liệu đó chỉ có tác dụng nhất thời ghi ra để tiến hành xuất dữ liệu ra file để lưu trữ.

Job này có nhiệm vụ xóa dữ liệu cũ của bảng, tổng hợp lại dữ liệu ở nhiều nguồn rồi insert dữ liệu vào bảng đó để thực hiện 1 số tác vụ tiếp theo.

Cách xử lý để Archived Log không phát sinh nhiều đó là thay vì việc job tiến hành xóa dữ liệu thì tiến hành truncate table. Vì truncate table coi như drop table và create lại, Archived Log không lưu trữ lịch sử thông tin truncate table nên Archived Log phát sinh rất ít.

Để thao tác truncate table thực hiện được trong procedure (gói gọn trong job) ta phải viết lệnh sau:

EXECUTE IMMEDIATE 'TRUNCATE TABLE tablename';

Từ phần này mình để ý từ lâu mà nay mới phát hiện ra. Mình có một table dữ liệu khá lớn tầm 20Gb, dữ liệu được thêm vào liên tục nên ngày càng phình to. Mình sử dụng Toad để xem dữ liệu và thỉnh thoảng xóa bớt dữ liệu đi nhưng sau đó kiểm tra kích thước cũng không bị giảm đi tẹo nào.
Mình đã thử việc xóa dữ liệu đi nhưng kích thước vẫn thế. Chỉ khi sử dụng lệnh truncate table thì kích thước table mới về 0.

Để ý các job tương tự sếp viết thì mình thấy sếp đều dùng câu lệnh truncate để xóa dữ liệu. Đúng là người có kinh nghiệm vẫn cứ khác.

Apex-Oracle: Phân quyền select cho table system

Ứng dụng phê duyệt theo quy trình của mình trên APEX cần thêm tính năng gửi email thông báo tới người nhận thông tin tiếp theo cũng như thông tin phê duyệt hoặc từ chối tới email của người dùng. Mình chỉ việc viết thêm hàm gửi email vào trong mỗi bước phê duyệt hoặc từ chối là xong. Code gửi email được viết bằng PL/SQL trên server Oracle mới đã có sẵn package đã được sử dụng từ trước rồi nhưng khi tiến hành dịch lại trên server này thì lại gặp lỗi thông báo bảng dba_directories không tồn tại. Lỗi này là do table không được phân quyền select trên Oracle.

Thực chất bảng dba_directories này là bảng của hệ thống nhưng với schema đang đăng nhập thì lại không có quyền gì thao tác trên bảng này. Đối với hàm gửi email cần truy cập bảng dba_directories để lấy đường dẫn nên ta phải tiến hành phân quyền select vào bảng dba_directories cho user (hay còn gọi là schema) chạy hàm gửi email này. Bởi vì bảng dba_directories là bảng của hệ thống nên ta phải sử dụng quyền sysdba để tiến hành phân quyền.

Sau đây là các bước phân quyền select cho table

Đối với server database Oracle chạy hệ điều hành Windown thì ta tiến hành các bước sau để phân quyền:

  • Bước 1: Login bằng tài khoản admin vào server database Oracle.
  • Bước 2: Mở cửa sổ command line cmd.exe lên
  • Bước 3: Bật sqlplus với quyền sysdba
    sqlplus “/ as sysdba”
  • Bước 4: Phân quyền select table cho user cần quyền select
    grant select on dba_directories to PKTUY_user;
  • Bước 5: Kết quả sau khi grant được thông báo là:
    Grant succeeded.

Sau khi đã phân quyền xong thì biên dịch lại package không còn bị lỗi nêu trên nữa.

Một số bài viết liên quan đến quản trị hệ thống Oracle:

Oracle Cách print in dữ liệu ra console để fix bug

Trong lĩnh vực SQL Developer trên Oracle, ta thường xuyên phải lập trình với function hoặc procedure hoặc đơn giản chạy một script lệnh nào đó. Thỉnh thoảng ta sẽ gặp các bug mà không biết lỗi xử lý ở bước nào. Các nhanh nhất để tìm và fix các bug này là việc ghi log ra console hoặc ghi log vào một bảng nào đó để xem. Mình thì cách đơn giản nhất đó là ghi log ra console.

Rất may trên công cụ Toad for Oracle thì có tính năng DBMS Ouput để ta có thể đọc log mà mình viết bằng câu lệnh DBMS_OUTPUT.PUT_LINE(‘text’). Mặc định trên Toad thì tính năng này bị Disable để tối ưu công cụ. Để bật nó lên ta vào thanh menu ở phía dưới màn hình soạn thảo code, chọn đến tab DBMS Ouput và click vào nút màu đỏ phía dưới. Khi tính năng DBMS Ouput được bật ta sẽ thấy cái nút màu đỏ vừa rồi chuyển sang màu xanh lá cây. Tại đây ta có thể chọn thời gian Toad làm mới để lấy log ra, mặc định là 5s một lần.

Dưới đây là câu lệnh ghi log trong SQL:

var_log VARCHAR(100):= 'log'
DBMS_OUTPUT.PUT_LINE('I got here:'||var_log||' is the new value');

Tạo hàm mã hóa SHA-256 trên Oracle 11g R2 (hashing-with-sha-256-in-oracle-11g-r2)

Hàm băm SHA1 đã được công bố đã bị phá mà không phải bằng thuật toán vét cạn.
Tất cả các mã hóa toàn vẹn dữ liệu của mã SHA-1 cần phải chuyển đổi sang bộ mã hóa cao cấp hơn ví dụ hàm SHA-256.

Trong hệ thống của công ty mình hiện đang sử dụng SHA-1 để mã hóa thông tin trước khi gửi sang đối tác, vì vậy cần phải nâng cấp sang hàm băm SHA-256.
Hàm băm SHA-256 chỉ có sẵn từ bản Oracle 12c, bản Oracle 11g sẽ không có. Có 2 cách để có được hàm băm SHA-256:
Cách 1: Sử dụng thư viện của Java có sẵn trong JDK để tạo nên hàm SHA-256
Tham khảo tại địa chỉ: https://dzone.com/articles/hashing-with-sha-256-in-oracle-11g-r2
Nhưng ở địa chỉ này chạy sẽ không được procedure do phải tắt tính năng define của Orcle đi.
Các bước lần lượt như sau:

B1: Tắt chế độ define

set define off


B2: Tạo tài nguyên class Java trong Oracle:

CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED test."calcsha"
    AS import java.security.MessageDigest; 
 public class calcsha2 
     {
         static public String fncsha(String inputVal) throws Exception
         {           
             MessageDigest myDigest = MessageDigest.getInstance("SHA-256");        
             myDigest.update(inputVal.getBytes());
             byte[] dataBytes = myDigest.digest();
             StringBuffer sb = new StringBuffer();
             for (int i = 0; i < dataBytes.length; i++) {
              sb.append(Integer.toString((dataBytes[i])).substring(1));
             }        
             StringBuffer hexString = new StringBuffer();
             for (int i=0;i<dataBytes.length;i++) {
                 String hex=Integer.toHexString(0xff & dataBytes[i]);
                     if(hex.length()==1) hexString.append('0');
                     hexString.append(hex);
             }
             String retParam = hexString.toString();
             return retParam;           
         }    
     }

B3: Viết thủ tục để gọi đến tài nguyên trên:

CREATE OR REPLACE FUNCTION test.hash_sha256 (txt varchar2)
 RETURN VARCHAR2
 AS
 LANGUAGE JAVA
 NAME 'calcsha2.fncsha(java.lang.String) return String';

B4: Bật trả chế độ define

 set define on

B5: Test kết quả:

 select hash_sha256('123456789') from dual;



So sánh với kết quả online: https://passwordsgenerator.net/sha256-hash-generator/

Cách 2: Cách này viết mới luôn hàm SHA-256 bằng PL-SQL
Tham khảo tại: https://github.com/CruiserX/sha256_plsql

Ta cũng có thể test kết quả so với cách 1.

Trưởng nhóm mình yêu cầu làm cách 2. Theo bản thân mình thì nên làm cách 1 vì toàn bộ là sử dụng thư viện chung JAVA của toàn thế giới, phần code tường minh. Còn cách 2 thì đi copy trên mạng về chạy cảm giác không được an toàn lắm.

APEX 5.x Thiết lập mặc định báo cáo trong Interactive Report

Trong quá trình duy trì và phát triển thêm các tính năng báo cáo của công ty sử dụng công cụ Apex, mình cần phải chỉnh sửa một báo cáo sử dụng loại có tên là Interactive Reoport.
Người dùng muốn bổ sung thêm cột dữ liệu mới ẩn bớt cột đi theo nghiệp vụ. Trong phần Page Designer mình đã thêm cột thành công nhưng gặp 2 vấn đề:

  • Không thể nào đặt các cột mới theo đúng vị trí mà mình muốn, mặc dù trong phần Columns đã kéo thả để sắp xếp
  • Không biết cách làm sao để query báo cáo vẫn có nhưng mặc định báo cáo hiển thị không có, khi nào người dùng cần thì dùng tính năng Actions -> Select column để có thể hiển thị.

Để hiển thị mặc định đối với tất cả các người dùng theo một form nhất định như thứ tự các cột cần hiển thị, danh sách các cột ẩn, danh sách các cột hiển thị thì ta dùng cách sau:

B1: Đăng nhập bằng tài khoản admin
B2: Vào giao diện ứng dụng của người dùng đầu cuối. Trong thanh menu tìm kiếm tùy chỉnh của báo cáo. Click Actions và thực hiện các thay đổi theo báo cáo mình cần hiển thị:

  • Select columns: Sắp xếp, lựa chọn các cột cần hiển thị.
  • Filter: Đặt các điều kiện để lọc dữ liệu
  • Rows per page: Cấu hình số dòng trên 1 trang…

B3: Lưu lại cấu hình mặc định này bằng cách vào Actions -> Save Report.
Mục Save chọn: As Default Report Setting sau đó chọn Apply.

Done. Tất cả các User khi truy cập báo cáo này sẽ được mặc định hiển thị dữ liệu theo cách mà ta đã cài đặt.

Vấn đề Unicode với Python 3- Oracle

Đối với Python 3 thì string tự động được sử dụng với Unicode nhưng khi sử dụng Tiếng Việt thao tác xuống Database Oracle hoặc hiển thị dữ liệu Tiếng Việt lên thì bị lỗi.

Để khắc phục điều này khi sử dụng connect tới DB thì cần khai báo encoding và nencoding: cx_Oracle.connect(‘admin’,’admin’,dsn_tns,encoding=”UTF-8″, nencoding=”UTF-8″)

Ví dụ hoàn thiện với việc thêm mới dữ liệu Tiếng Việt:

#!/usr/bin/python

# -*- coding: utf8 -*-
from unicodedata import normalize
import cx_Oracle
cursor, connection = None, None
try:
    dsn_tns = cx_Oracle.makedsn('192.168.177.xxx' , 1522, 'orcl')
    connection = cx_Oracle.connect('admin','admin',dsn_tns,encoding="UTF-8", nencoding="UTF-8")
    cursor = connection.cursor()
    a=u"Lý do"
    b="reasons"
    c="INSERT INTO VN_TEMP_DIC (VN, EN,DAY_TIME,STATUS) VALUES ('%s','%s',sysdate,0)" % (a,b)
    cursor.execute(c)
    cursor.execute("COMMIT")
except cx_Oracle.DatabaseError as e:
    raise e
except Exception as e:
    raise e     
finally:
    if cursor != None:
        cursor.close()
    if connection != None:
        connection.close()


    

Ví dụ hoàn thiện với việc hiển thị dữ liệu tiếng Việt load từ DB:

#!/usr/bin/python
# -*- coding: utf8 -*-

import cx_Oracle
dsn_tns = cx_Oracle.makedsn('xxxxxxxxx' , 1522, 'orcl')
connection = cx_Oracle.Connection('admin','admin',dsn_tns,encoding="UTF-8", nencoding="UTF-8")
cur=connection.cursor()
content = 'however it not depend on column INDPOSTPONEADVANTAGES'
listword=content.split()
listr="";
for re in listword:
    listr=listr+"','"+re
listr=listr
listr=listr[3:]   
print(listr)
query="select a.EN,a.VN from VN_TEMP_DIC a where trim(a.EN) in('%s') order by a.STATUS desc,a.DAY_TIME desc" % (listr)
#print(query)
cur.execute(query)
for result in cur:
    print(result[0]+" - "+result[1])
cur.close()
connection.close

Một số tài liệu cài đặt Oracle trên Oracle Linux

https://asktom.oracle.com/pls/asktom/asktom.search?tag=ora-01034-oracle-not-available

https://oracle-base.com/articles/linux/automating-database-startup-and-shutdown-on-linux

ORA-01078: failure in processing system parameters

https://stackoverflow.com/questions/18403125/how-to-create-a-new-schema-new-user-in-oracle-database-11g

Cài đặt từ thư viện Oracle

https://sites.google.com/site/loilmsite/oracle/cai-dat-oracle-database-11g-release-2-tren-oracle-linux-6

https://ora-data.blogspot.com/2016/11/sqlplus-not-connecting-in-oracle.html

https://community.oracle.com/thread/2178662

Oracle đã và đang ứng dụng trí tệ nhân tạo trong sản phẩm Database

Nghe thiên hạ đồn oracle đang phát triển thế hệ Database mới với ứng dụng trí tuệ nhân tạo trong đó. Trí tuệ nhân tạo sẽ giúp hệ thống tự động nhận diện các lỗi phát sinh trong hệ quản trị cơ sở dữ liệu và tiến hành tự sửa chữa. Việc ứng dụng AI này hệ thống Database sẽ cần ít thao tác từ người quản trị hơn mà sẽ tự động quản trị, ví dụ như:

  • Trước đây người quản trị (DBA) sẽ theo dõi hệ thống và ra các quyết định tác động lên hệ thống, ở mức cao hơn sẽ tự động hóa bằng các job hay tool để monitor và tự xử lý với các rule đặt trước. Nhưng trí tuệ nhân tạo sẽ hoàn toàn bỏ qua phần này, hệ thống sẽ tự động xác định và xử lý mà không cần sự can thiệp của DBA.
  • Việc tinh chỉnh, tối ưu, turning câu lệnh SQL sẽ được hệ thống ứng dụng trí tuệ nhân tạo xác định và tiến hành tối ưu. Hệ thống sẽ tự phân tích để đánh index, tạo view, sử dụng bảng tạm, bảng phẳng để tối ưu các tiến trình.
  • Trí tuệ nhân tạo sẽ tự tối ưu các job, đồng bộ dữ liệu, cân bằng tải… tự đưa ra các chiến lược backup hiệu quả để tiết kiệm tài nguyên và tăng tính sẵn sàng cho hệ thống…
  • Việc lấy các báo cáo sẽ nâng cao tính động, nhanh hơn và có thể hiểu người ra yêu cầu một cách chính xác hơn.

Nhìn chung sẽ làm cho hệ thống Database trở nên thông minh hơn, công việc DBA sẽ nhẹ nhàng và nhàn hạ đi rất nhiều nhưng cùng với đó là công việc DBA sẽ ít dần và dần chuyển sang công việc khác. Tất nhiên con đường đó vẫn còn xa, việc tự động hóa toàn bộ cũng nảy sinh nhiều vấn đề mà khó có thể lường trước được.

Winservice và Job scheduler – crontab

Hôm trước có đồng nghiệp cũ hỏi mình config thời gian chạy của winservice tự động gửi lại tin nhắn nằm ở đâu? Thực ra vòng vo một hồi thì đó là 1 cái Job chạy 5 phút 1 lần kiểm tra xem hàng đợi gửi tin nhắn xử lý có bị tồn không để thông báo tới admin để kiểm tra hệ thống. Về hệ thống này mình sẽ trình bày ở một bài khác.
Nhân tiện việc này mình muốn chia sẻ sự hiểu biết của mình về Winservice và Scheduler – Crontab:

  • Winservice: mình đã tiếp xúc với winservice sớm hơn trong công việc. Winservice bản chất là một chương trình thực thi một khối lệnh nào đó hoặc công việc nào đó lặp đi lặp lại sau một khoảng thời gian nghỉ nào đó. Ví dụ như ta phải dán con hạc giấy đã được gấp lên một bước tường chẳng hạn, ta cứ dán được 1 con lên thì ta lại ngồi nghỉ 5 phút chẳng hạn. Ta không quan tâm dán nó trong bao lâu 1 phút, 2 phút hay 5 phút… miễn là cứ dán xong thì ta ngồi nghỉ 5 phút rồi dán tiếp. Ứng dụng của Winservice là xử lý hàng đợi – queue, trong hàng đợi ta không cần biết có bao nhiêu, cứ lấy 1 cái (có thể random hoặc cái đầu hàng đợi hoặc cuối hàng đợi…) đem ra để xử lý xong rồi nghỉ một thời gian nào đó rồi lại vào lấy 1 cái… tất nhiên hàng đợi có thể tiếp tục được cập nhật hoặc không, hoặc có thể cập nhật ở một thời điểm bất kỳ nào đó. Do vậy với winservice ta không thể biết trước khi nào thì một khối lệnh hoặc công việc mới được thực hiện do ta không nắm được khối lệnh đó hoặc công việc được xử lý trong bao lâu. Cứ phải xong thì mới thực hiện các việc tiếp theo. Đối với Winservice ta có thể làm xử lý 1 luồng nhưng để hiệu quả ta có thể làm nó chạy đa luồng (nghĩa là các công việc xử lý song song nhau) nhưng nếu sử dụng chung tài nguyên thì rất dễ xảy ra xung đột dẫn đến bị deadlock và winservice bị treo không chạy được nữa. Ta buộc phải xử lý khéo léo khi code trong vấn đề này, và việc này xảy ra là chuyện bình thường.
  • Scheduler – Crontab: Cũng như Winservice, Scheduler – Crontab (mình không rõ tên của nó nên đang dùng tên lần lượt mà hệ đều hành Window và Linux cung cấp cho người dùng) cũng thực thi một khối lệnh hoặc công việc nào đó nhiều lần nhưng được xác định thời gian bắt đầu của công việc đó. Ví dụ với việc dán hạc giấy, thì cứ đầu từng giờ ta tiến hành dán một con hạc giấy, việc dán này không cần biết có xong hay không, nhanh hay chậm, cứ đầu từng giờ là lấy 1 con hạc lên gián mà thôi. Như vậy có thể lần giờ trước ta dán chưa xong thì tới lần giờ tiếp theo ta sẽ vẫn lấy 1 con hạc đem đi dán.

Một số ứng dụng của Winservice và Scheduler – Crontab mà mình biết như sau:

Winservice:

  • Xử lý hàng đợi nạp tiền của khách hàng: Ví dụ hàng trăm nghìn tin nhắn nạp thẻ đến trong 1 phút của nhà mạng, nhà mạng chắc chắn sẽ dựng queue để đón nhận các yêu cầu này và lần lượt lấy 1 hoặc 1 số giao dịch để đem đi xử lý. Có thể nghỉ 1 chút lại tiếp tục lấy để xử lý……

Scheduler – Crontab: Các phần job chạy theo năm – tháng – giờ – phút – giây như:

  • Job backup hệ thống vào cuối mỗi ngày
  • Job kiểm tra cứ 5 phút lại check hệ thống hoặc tác vụ gì đó như winservice còn sống không để thông báo
  • Job gửi dữ liệu vào ngày đầu tháng tất cả số liệu của tháng trước

Winservice và Scheduler – Crontab có các tính chất và ưu nhược điểm khác nhau nên tùy từng tác vụ cụ thể ta phải xem xét và sử dụng cho phù hợp.

Oracle thông báo về các Procedure, PACKAGE được sửa trong ngày

Một ngày đẹp trời như thường lệ mình đến công ty nhưng được thông báo là có 1 vài job chạy hàng đêm của hôm trước bị lỗi. Kiểm tra nguyên nhân thì do mình đã tiến hành sửa một PACKAGE nhưng khi compile thì bị lỗi mà mình đã không để ý. Đó chính là sơ suất của mình khi thực hiện sửa 1 PACKAGE trên PROD mà không verify lại. Để khắc phục hậu quả này là phải đi tìm lại đoạn code bị mất trên con test (mà đã backup rồi) và tiến hành chạy lại những job bị lỗi.

Để kiểm soát việc này, vào cuối ngày ta phải check lại các PACKAGE được sửa đổi trong ngày có compile thành công hay không. Sau đây là câu lệnh liệt kê các PACKAGE, PROCEDURE được sửa trong ngày:

SELECT owner,
object_name,
object_type,
last_ddl_time,
status
FROM dba_objects
WHERE object_name IN
(SELECT A.REFERENCED_NAME
FROM DBA_DEPENDENCIES a
WHERE object_type IN ('PROCEDURE', 'PACKAGE BODY', 'PACKAGE'))
AND last_ddl_time >= TRUNC(SYSDATE - 1)
ORDER BY last_ddl_time DESC;

Để tự động hóa việc này ta tiến hành lập crontab hoặc schedule gửi email thông tin để người trực cuối ngày kiểm tra để tiến hành sửa kịp thời. Tránh bị lỗi như trên.