DELETE, TRUNCATE và DROP khác nhau thế nào?
DELETE (DML) xoá từng dòng theo WHERE, có thể rollback và kích hoạt trigger. TRUNCATE xoá toàn bộ dòng nhanh, reset bộ đếm identity, không có WHERE. DROP xoá cả bảng gồm cấu trúc, index, ràng buộc.
INNER, LEFT, RIGHT, FULL JOIN khác nhau thế nào?
INNER lấy các dòng khớp ở cả hai bảng; LEFT giữ mọi dòng bảng trái (không khớp thì NULL); RIGHT ngược lại; FULL giữ tất cả dòng của cả hai.
NULL trong SQL gây những cạm bẫy nào?
NULL nghĩa là không xác định: mọi so sánh với NULL (kể cả NULL = NULL) cho UNKNOWN, nên phải dùng IS NULL. NOT IN với danh sách chứa NULL không trả dòng nào; hàm tổng hợp bỏ qua NULL (trừ COUNT(*)).
Thứ tự thực thi logic của một câu SELECT là gì?
Thứ tự logic: FROM/JOIN, WHERE, GROUP BY, HAVING, SELECT, DISTINCT, ORDER BY, LIMIT. Vì vậy alias khai báo ở SELECT không dùng được trong WHERE nhưng dùng được trong ORDER BY.
WHERE và HAVING khác nhau thế nào?
WHERE lọc từng dòng trước khi GROUP BY nên không dùng được hàm tổng hợp; HAVING lọc các nhóm sau khi GROUP BY nên dùng được COUNT, SUM, AVG. Nên lọc sớm bằng WHERE để giảm số dòng phải gom nhóm.
ACID là gì? Transaction dùng để làm gì?
ACID: Atomicity (all-or-nothing), Consistency (giữ ràng buộc), Isolation (giao dịch song song không ảnh hưởng nhau), Durability (đã commit thì không mất).
Chuẩn hoá 1NF-3NF là gì và khi nào nên denormalize?
1NF: giá trị nguyên tử, không nhóm lặp. 2NF: không phụ thuộc một phần vào khoá ghép. 3NF: không phụ thuộc bắc cầu vào thuộc tính không khoá. Chuẩn hoá giảm trùng lặp và bất thường khi ghi; denormalize đánh đổi để đọc nhanh hơn.
Index trong database là gì? Khi nào làm chậm hệ thống?
Index là cấu trúc dữ liệu (thường B-Tree) giúp tìm dòng nhanh mà không quét toàn bảng; đổi lại tốn dung lượng và làm INSERT/UPDATE/DELETE chậm hơn.
PRIMARY KEY, FOREIGN KEY và các constraint chính
PRIMARY KEY định danh duy nhất mỗi dòng (UNIQUE + NOT NULL, một bảng chỉ có một). FOREIGN KEY ràng buộc tham chiếu sang khoá bảng khác, kèm hành vi ON DELETE. Ngoài ra có UNIQUE, NOT NULL, CHECK, DEFAULT để bảo vệ dữ liệu ngay ở DB.
Subquery và CTE (WITH) khác nhau thế nào?
Subquery lồng trong câu lệnh chính; CTE (WITH) đặt tên cho tập kết quả tạm, giúp câu truy vấn dễ đọc, tái sử dụng trong cùng câu lệnh và hỗ trợ đệ quy. Hiệu năng thường tương đương, tuỳ optimizer có inline hay materialize CTE.
Vấn đề N+1 query là gì? Cách khắc phục?
N+1 là chạy 1 query lấy danh sách rồi N query nữa cho từng phần tử. Khắc phục bằng JOIN, eager loading, hoặc gom id và query một lần bằng WHERE IN.
Window function: ROW_NUMBER, RANK, LAG dùng thế nào?
Window function tính toán trên một cửa sổ dòng (OVER, PARTITION BY, ORDER BY) mà không gộp dòng như GROUP BY. ROW_NUMBER đánh số duy nhất, RANK chừa khoảng trống khi đồng hạng, DENSE_RANK không chừa, LAG/LEAD lấy dòng trước/sau.
Đọc EXPLAIN / query plan để tối ưu truy vấn chậm
EXPLAIN cho thấy kế hoạch thực thi optimizer chọn; EXPLAIN ANALYZE chạy thật và báo thời gian, số dòng thực tế. Cần chú ý Seq/Full scan vs Index scan, kiểu join, chênh lệch giữa rows ước lượng và thực tế (thống kê lỗi thời), và bước sort tốn kém.
Isolation level và deadlock trong SQL
Isolation level quyết định hiện tượng đọc cho phép: dirty read, non-repeatable read, phantom read. Từ READ UNCOMMITTED đến SERIALIZABLE càng chặt càng ít bất thường nhưng giảm đồng thời. Deadlock xảy ra khi hai transaction giữ lock chờ nhau; tránh bằng thứ tự lock nhất quán, transaction ngắn, retry.
Optimistic locking và pessimistic locking khác nhau thế nào?
Pessimistic khoá dòng ngay khi đọc (SELECT ... FOR UPDATE) để chặn xung đột, phù hợp khi tranh chấp cao. Optimistic không khoá, dùng cột version và kiểm tra khi UPDATE; nếu 0 dòng bị ảnh hưởng thì xung đột và phải retry, phù hợp khi tranh chấp thấp.
Phân trang OFFSET và keyset (seek) khác nhau thế nào?
OFFSET n phải quét rồi bỏ n dòng nên càng sang trang sâu càng chậm và dễ lệch dữ liệu khi có insert/delete. Keyset dùng điều kiện trên khoá đã sắp xếp (WHERE id < last_id) nên dùng index, thời gian ổn định, nhưng không nhảy được tới trang bất kỳ.