Tối ưu câu lệnh SQL: Oracle so sánh thời gian

Ở bài viết Oracle so sánh thời gian ngày tháng – Oracle compare date time mình có chia sẻ về cách ta có thể so sánh thời gian trong Oracle. Nhưng trong quá trình triển khai thực thế, việc turning hệ thống thì thấy việc sử dụng các câu lệnh này sẽ có vấn đề về index trên cột này. Ta cùng phân tích và tối ưu câu lệnh SQL cho vấn đề này nhé.

Đối với câu lệnh PL/SQL, cụ thể là Oracle thì hàm to_char(…) gây mất index đối với cột dữ liệu kiểu DATETIME. Tương tự với việc sử dụng toán tử LIKE cho kiểu dữ liệu VARCHAR hoặc NVARCHAR. Nhưng đổi lại việc sử dụng hàm TRUNC lại không làm mất index kiểu dữ liệu DATETIME.
Để tối ưu câu lệnh phải so sánh thời gian ta tránh việc sử dụng hàm to_char(…) để tránh mất index column này. Mặc dù ta nhìn câu lệnh SQL khi turning seckhông được tường minh và dễ hiểu lắm. Đúng thôi, ta buộc phải đánh đổi, cuộc sống mà.

Cách tối ưu khi so sánh ngày tháng

– So sánh ngày:

Kiểu cũ: Ta tiến hành convert dữ liệu dạng ngày sang kiểu string và tiến hành so sánh:

ví dụ:
Cần lấy ngày tạo lớn hơn hoặc bằng ngày 06/04/2018

AND TO_CHAR(datecreate, ‘YYYYMMDD’) >= ‘20180406’;

Turning: Ta có thể viết lại hàm này một chút để nó sẽ chạy nhanh hơn, tránh gây ảnh hưởng hiệu năng hệ thống.
Như câu lệnh trên ta có thể thấy ta đã đều ép kiểu dữ liệu về String để so sánh rồi, chính việc luôn phải convert dữ liệu từ kiểu DATETIME về kiểu String nên việc này sẽ ảnh hưởng đến chỉ số CPU. Ta sẽ để việc so sánh này về so sánh bằng kiểu DATETIME, nghĩa là ta sẽ chuyển đối tượng so sánh về kiểu thời gian, cụ thể câu lệnh trên được viết lại thành:

AND TRUNC(datecreate) >= TO_DATE(‘20180406’,'YYYYMMDD');

Như vậy, hàm TO_DATE(‘20180406’,'YYYYMMDD') chỉ phải sử dụng 1 lần duy nhất để chuyển kiểu String về kiểu DATETIME để so sánh. Hàm TRUNC sẽ không gây mất index mà đơn giản để chính xác ta để nó về thời gian đầu tiên của ngày, nghĩa là 0h 00p.

Hoặc trong khoảng ngày cũng tương tự:
Cách 1:
AND TRUNC(datecreate) >= TO_DATE(‘20180406’,'YYYYMMDD')
AND TRUNC(datecreate) < TO_DATE(‘20180411’,'YYYYMMDD')

– So sánh ngày chi tiết tới thời gian:

Kiểu cũ: Ta tiến hành convert dữ liệu dạng ngày sang kiểu string và tiến hành so sánh:

ví dụ:

Cần lấy ngày tạo lớn hơn hoặc bằng 7h tối ngày 06/04/2018:

AND TO_CHAR(laa.datcre, ‘YYYYMMDD HH24:MI:SS’) >= ‘20180406 19:00:00’

Turning: Việc này thì ta cũng làm tương tự như trên nhưng cần lưu ý xử lý về vấn đề thời gian giờ – phút – giây. Việc chuyển định dạng thời gian này hơi phức tạp, mình sẽ nghiên cứu và bổ sung thêm.

Tối ưu câu lệnh SQL không chỉ tập trung vào các cú pháp và hướng xử lý như việc tối ưu trên mà ta còn cần phải chú ý tới dữ liệu ta sử dụng. Đối với những dữ liệu khi cần tìm kiếm nhiều ta cũng cần quan tâm đến việc đánh Index và bố trí phân vùng cho chúng được hợp lý và tốt hơn.

Oracle: Điều kiện về biến trong mệnh đề Where

Hôm nay làm việc thì có chị trong team đố về việc viết 1 thủ tục Oracle như sau:
Có một bảng dữ liệu gồm 4 cột Họ Tên, Số điện thoại, Số CMT và Email. Viết thủ tục đếm xem có bao nhiêu người thỏa mãn 3 tiêu chí mà người dùng nhập vào là Số điện thoại, Số CMT và Email (người dùng có thể nhập hoặc không nhập bất cứ thông tin ở tiêu chí nào cả).

Ban đầu tiếp cận cũng thấy dễ nhưng dần dần cũng khoai. Hướng triển khai ban đầu sử dụng cách check điều kiện có nhập hay không trước sau đó tiến hành nối thành một query cuối cùng.

Phần check điều kiện null:

condition:='';
if P_SDT is not null then
condition:= condition || ' AND SDT='||P_SDT;
end if;
if P_EMAIL is not null then
condition:= condition || ' AND EMAIL='||P_EMAIL;
end if;
if P_CMT is not null then
condition:= condition || ' AND CMT='||P_CMT;
end if;

Phần nối câu lệnh để run:

select count(*) into w_count
from NGUOI_DUNG from 1=1 || condition;

Câu lệnh này không thể thực thi được, Oracle không hiểu được để xử lý khi nối chuỗi vào câu lệnh SQL.

hoặc áp dụng chính câu lệnh kiểm tra trong mệnh đề Where:

select count(*) into w_count
from NGUOI_DUNG from 1=1
AND (P_CMT is not null AND CMT=P_CMT)
AND (P_EMAIL is not null AND EMAIL=P_EMAIL)
AND (P_SDT is not null AND SDT=P_SDT)
;

Câu lệnh này không thực thi được do nó luôn thực thi cả phần ngoặc trong AND (Ban đầu mình ngây thơ là trong cả cái AND to, cái CMT=P_CMT sẽ được thực thi khi cái P_CMT is not null đúng) 🙁

Xử nhiều cách khác nhau nhưng đều không được, tra Google thì không tìm được giải pháp khả dĩ do chưa có được từ khóa phù hợp.
Cuối cùng cũng tìm ra một phương pháp khả dĩ và sử dụng được như sau:

select count(*) into w_count
from NGUOI_DUNG from 1=1
and (
SDT=(CASE
WHEN P_SDT is not null THEN P_SDT
ELSE SDT
END
)
)
and (
EMAIL=(CASE
WHEN P_EMAIL is not null THEN P_EMAIL
ELSE EMAIL
END
)
)
and (
CMT=(CASE
WHEN P_CMT is not null THEN P_CMT
ELSE CMT
END
)
)
;

Phần này quan trong ở điểm nếu P_CMT is not null đúng thì CMT=P_CMT còn ngược lại thì mệnh đề CASE WHEN trả về chính CMT để CMT=CMT, 2 cột dữ liệu trung tên thì như điều kiện 1=1 nên nó luôn đúng.

Từ phần này có thể đơn giản hóa bằng câu lệnh NVL, CMT=NVL(P_CMT,CMT,P_CMT). Nhưng viết thế này người nào không rõ về NVL sẽ không hiểu lắm. Cách trên tuy dài nhưng dễ hiểu hơn.

Công cụ tra số điện thoại của facebook người dùng

Xuất phát từ bài viết của anh C Chủ Chứa trước cùng xóm trọ hơn mình 2 khóa. Anh trước code Object-C cho FPT, sau đó đầu quân cho Đại học Đại Nam ở vị trí chiêu sinh (tuyển sinh). Bài viết Share tool có thể check số điện thoại của bất kỳ tài khoản facebook nào -> kinh chưa?
Theo mình biết không thể lấy thông tin đó nếu người dùng ẩn số điện thoại, đó là việc bảo vệ dữ liệu người dùng của facebook. Nhiều người thách thức đều đã bị khuất phục(đều là dân IT và cũng biết cái mà mình biết). Do số của mình lại tạo facebook cho con Hà Phai nên mình thách thức anh đấy để thử tính năng.
Tất nhiên là không tìm được, tò mò mình hỏi cách làm. Vỡ lẽ ra không phải là việc hack được hoặc gì gì đó về kỹ thuật. Mà là ông đấy đã có data của 6 triệu tài khoản chưa ID facebook và số điện thoại. Để lấy các ông đấy chỉ việc so sánh theo ID facebook mà ra được số thôi.
Cái hay và tài ở đây là trước đây facebook chưa tiến hành ẩn các thông tin này đi, các bác đó đã tiến hành quét toàn bộ và đã lấy được các thông tin này. Bây giờ có muốn lấy cũng không được nữa và facebook đã đóng các API này lại. Việc này trước mình làm 1 công ty, đối tác trong buổi chào hàng về Bigdata đã tiến lộ họ đã craw được cái tương tự mà các bác kia làm. Kinh khủng thật.
Mình có kể điều này với 1 đứa em, nó nói đúng là có thằng nó nghĩ ra. Đã phần bọn còn lại như mình là không nghĩ cái mình đang dùng ngon ơ sau đó sẽ bị mất hoặc giới hạn đi.

Trở lại vụ trên theo anh C Chủ Chứa thì cái kết quả data số điện thoại với facebook cũng chưa kiếm được ra tiền vì có facebook rồi biết số điện thoại cũng không có nhiều ích lợi lắm, hơn nữa như kỹ thật anh đấy nói việc quét 6 triệu bản ghi thì quá lớn và không làm được(? mình vẫn làm với số liệu còn khủng khiếp hơn nhiều, 6 triệu ăn thua gì).

Nhưng nếu xử lý được thì làm sao? Làm thế nào kiếm được tiền. Theo ý mình thì là dùng cho bọn bán hàng online, có facebook like hoặc quan tâm thì mình có thể lấy số điện thoại để tư vấn tiếp qua SMS hoặc TeleSale. Nhưng anh đấy chia sẻ là hiệu quả không cao, chỉ có mấy thằng nhà đất mới đủ tiềm lực để mua và dùng thôi vì lợi nhuận của nó lớn. Nó cần data nhiều. Như anh chia sẻ tiếp là như anh đấy làm tuyển sinh cũng không thể sử dụng data đó được.

Cũng nhiều cái học được từ vụ này, đúng là đi một ngày đàng học một sàng khôn nhỉ. 😀 Nao đi bia với ông này 1 hôm mới được.

Hướng tiếp cận bài toán bằng cách vét cạn từng Số nguyên tố

Một bài học quý báu mà thầy Thắng có truyền lại cho đội O trong kỳ thi Olympic như sau:
Vào một năm nào đó, kỳ thi của đội anh Hinh hay anh Hùng dự ACM-ICPC có bài toán cần giải đại loại là cho 1 khoảng và in ra các số nguyên tố trong khoảng đó. Tất nhiên kết quả phải được đưa ra dưới x giây.
Xét về kỹ thuật thông thường ta buộc phải kiểm tra từng số trong khoảng đó và xác định xem đó là có phải số nguyên tố hay không? Với bài toán kinh điển kiểm tra có phải số nguyên tố hay không thì có nhiều thuật toán, nhưng số càng lớn thì càng cần nhiều thời gian hơn để kiểm tra. Và việc xử lý vấn đề thời gian là yếu tố quan trọng nhất vì với các thuật toán hiện tại thì không thể xử lý được trong khoảng thời gian mà ban tổ chức đưa ra…
Vì thi ACM-ICPC không chấm thuật toán mà tính pass hay không thông qua tập test của ban tổ chức. Tất nhiên nếu có danh sách tập test và kết quả của ban tổ chức thì chỉ cần IF ELSE cũng đạt điểm.
Một ý tưởng xử lý rất thông minh đó là ta tiến hành liệt kê ra 1 tập sẵn các số nguyên tố nằm trong phạm vi của đề của ban tổ chức trước, sau đó chương trình chỉ cần đọc file và lấy danh sách số nguyên tố trong khoảng mà đề bài yêu cầu. Độ phức tạp sẽ O(n).
Kết quả của đội là đã giải thành công bài toán, bài đã chấp nhận, file sinh danh sách số nguyên tố gần 1GB, mất gần hết thời gian cả cuộc thi.

Đây là bài toán kinh điển về kinh nghiệm xử lý vấn đề, nó thay đổi tư duy và cách tiếp cận bài toán. Cũng như là phải hiểu rõ phương thức và hoàn cảnh. Nó có thể ứng dụng trong nhiều trường hợp trong công việc và đời sống.

P/S: Tất nhiên cách này không thể áp dụng được trong cuộc thi Olympic vì cuộc thi Olympic là cuộc thi thuật toán, khi ta chưa thể code được chương trình nhưng ta đưa ra được quan điểm, giải thuật xử lý đúng đắn thì ban tổ chức vẫn có thể cộng điểm cho chúng ta.
Với bài toán trên nếu giới hạn dung lượng file thì cũng không thể đạt điểm cho bài toán này.

Máy có thể vẽ bằng bút theo một định dạng cho trước với AxiDraw

Trong quá trình làm luận văn về sử dụng sóng não để điều khiển thiết bị thông qua Emotiv. Thầy Vĩnh có đưa ra ý tưởng vẽ lại một bức ảnh gì đó đã được nhìn thấy trong quá khứ. Ý thầy sử dụng Emotive là thiết bị đọc sóng não kết hợp với thiết bị vẽ AxiDraw.

Ý tưởng này để hậu xét nhưng thấy thằng AxiDraw cũng khá hay ho. Là một thiết bị ứng dụng IOT mà điển hình là Adruino.

The AxiDraw V3 Drawing machine by Evil Mad Scientist. AxiDraw.com