Courses
Bạn có để ý rằng MySQL hầu như luôn xuất hiện trong mọi mô tả công việc liên quan đến cơ sở dữ liệu không? Điều đó có lý do rõ ràng — MySQL gần như vận hành mọi thứ, từ các nền tảng mạng xã hội yêu thích của bạn đến các ứng dụng bạn dùng hằng ngày.
Tôi đã biên soạn hướng dẫn này để giúp bạn chinh phục các câu hỏi phỏng vấn MySQL. Tôi sẽ bao quát mọi khía cạnh, từ những điều căn bản mà lập trình viên junior cần biết đến các chủ đề phức tạp cho vị trí senior. Ngoài ra, tôi sẽ chia sẻ vài mẹo giúp bạn thể hiện sự tự tin trong các buổi phỏng vấn liên quan đến dữ liệu sắp tới.
MySQL Là Gì?
MySQL là hệ quản trị cơ sở dữ liệu quan hệ (RDBMS) mã nguồn mở được xây dựng trên SQL, tổ chức dữ liệu thành các bảng có cấu trúc. Nó được phát triển bởi Oracle Corporation.
MySQL xếp hạng là DBMS phổ biến nhất năm 2024. Tuy nhiên, một khảo sát Nhà Phát Triển của Stack Overflow năm 2025 cho thấy PostgreSQL đứng đầu về mức độ sử dụng trong số các nhà phát triển chuyên nghiệp, lần đầu tiên vượt qua MySQL.
Đừng hiểu lầm: MySQL vẫn cực kỳ phổ biến — đạt mức sử dụng 40,5% trong giới nhà phát triển vào năm 2025 — và vẫn vận hành vô số ứng dụng web, hệ thống quản lý nội dung và công cụ doanh nghiệp. Đặc biệt nếu bạn làm việc với ứng dụng web hoặc ngăn xếp LAMP, MySQL là một kỹ năng hàng đầu nên có.

Năm 2024, MySQL là DBMS mã nguồn mở phổ biến nhất thế giới, với điểm xếp hạng 1061. Nguồn: Statista.
Câu Hỏi Phỏng Vấn MySQL Cơ Bản
Ở giai đoạn phỏng vấn ban đầu, nhà tuyển dụng có thể hỏi các câu cơ sở để đánh giá hiểu biết của bạn về khái niệm cơ sở dữ liệu và MySQL.
1. Cơ sở dữ liệu là gì và khác gì so với DBMS?
Cơ sở dữ liệu là một kho lưu trữ chứa dữ liệu mà chúng ta có thể truy cập, sửa đổi và phân tích. Ví dụ, các nền tảng mạng xã hội lưu dữ liệu về người đã thích bài đăng của chúng ta trong các cơ sở dữ liệu.
DBMS (Hệ Quản Trị Cơ Sở Dữ Liệu) là phần mềm cho phép chúng ta tương tác và quản lý dữ liệu đó bằng cách tạo người dùng và quản lý quyền truy cập của họ. MySQL là một trong những lựa chọn DBMS phổ biến nhất. Các ví dụ khác bao gồm PostgreSQL, MongoDB và Microsoft SQL Server.
2. MySQL khác gì so với các hệ quản trị cơ sở dữ liệu quan hệ khác?
MySQL là hệ quản trị cơ sở dữ liệu quan hệ (RDBMS) mã nguồn mở dùng SQL để quản lý dữ liệu. Nó nổi tiếng nhờ dễ sử dụng, tốc độ và khả năng tương thích với các ứng dụng web.
MySQL khác gì so với các RDBMS khác:
- Đơn giản và hiệu năng: MySQL thường được khen ngợi vì tính đơn giản và hiệu năng tối ưu, khiến nó trở thành lựa chọn ưa thích cho lập trình viên web và startup.
- Tính năng nâng cao: Dù MySQL vượt trội về tính dễ dùng, nó có thể thiếu một số tính năng nâng cao ở các RDBMS khác như PostgreSQL, chẳng hạn hỗ trợ giao dịch ACID toàn diện hơn, lập chỉ mục nâng cao và tập kiểu dữ liệu rộng hơn.
- Bộ máy lưu trữ: MySQL cho phép bạn chọn các bộ máy lưu trữ khác nhau (ví dụ: InnoDB, MyISAM) cho từng bảng, mang lại sự linh hoạt cho các trường hợp sử dụng cụ thể.
MySQL lý tưởng cho các tình huống yêu cầu tốc độ và khả năng mở rộng, nhưng với các tính năng phức tạp hoặc cấp doanh nghiệp, PostgreSQL có thể là lựa chọn tốt hơn.
3. Các kiểu dữ liệu chính có trong MySQL là gì?
MySQL hỗ trợ nhiều kiểu dữ liệu được phân loại như sau:
-
Số học:
INT,DECIMAL,FLOAT,DOUBLE, v.v. -
Chuỗi:
CHAR,VARCHAR,TEXT,BLOB. -
Ngày/giờ:
DATE,DATETIME,TIMESTAMP,TIME. -
JSON: Dùng để lưu đối tượng JSON.
4. Sự khác nhau giữa kiểu dữ liệu INT và DECIMAL là gì?
INT lưu số nguyên không có phần thập phân. Ta có thể dùng khi không cần phần lẻ. Ngược lại, DECIMAL có thể lưu giá trị tài chính và phù hợp cho các phép tính thập phân chính xác.
5. DATE khác gì với DATETIME trong MySQL?
Hàm DATE trong MySQL lưu ngày theo định dạng năm, tháng, ngày:
YYYY-MM-DD
Trong khi đó, DATETIME lưu ngày kèm thời gian, trông như sau:
YYYY-MM-DD HH:MM:SS
6. Khóa ngoại là gì và bạn sẽ dùng nó như thế nào trong cơ sở dữ liệu?
Khóa ngoại là một trường trong bảng này liên kết đến khóa chính của bảng khác.
Ví dụ, trong bảng customers lưu thông tin khách hàng, mỗi khách có customer_id duy nhất — trong bảng khác tên transactions (lưu lịch sử mua), ta dùng customer_id làm khóa ngoại. customer_id trong bảng transactions sẽ liên kết mỗi lượt mua với một khách hàng cụ thể trong bảng customers .
Cách thể hiện bằng SQL như sau:
CREATE TABLE customers (
customer_id INT PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(100)
);
CREATE TABLE transactions (
transaction_id INT PRIMARY KEY,
customer_id INT,
amount DECIMAL(10,2),
date DATE,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);
7. Sự khác nhau giữa INNER JOIN, LEFT JOIN, RIGHT JOIN và FULL JOIN là gì?
JOIN kết hợp các hàng từ hai hoặc nhiều bảng dựa trên cột liên quan. Khác biệt như sau:
-
INNER JOIN: Trả về các hàng có khớp ở cả hai bảng.
-
LEFT JOIN: Trả về tất cả hàng từ bảng bên trái và các hàng khớp từ bảng bên phải. Nếu không có khớp, các cột của bảng bên phải trả về
NULL. -
RIGHT JOIN: Tương tự
LEFT JOIN, trả về tất cả hàng từ bảng bên phải và các hàng khớp từ bảng bên trái. -
FULL JOIN: Kết hợp kết quả của
LEFT JOINvàRIGHT JOIN, bao gồm cả các hàng không khớp từ cả hai bảng. Lưu ý: MySQL không hỗ trợ cú phápFULL JOINmột cách nguyên bản. Để đạt cùng kết quả, hãy dùngUNIONgiữaLEFT JOINvàRIGHT JOIN
8. Sự khác nhau giữa DELETE, TRUNCATE và DROP trong MySQL?
Các lệnh như DELETE, TRUNCATE và DROP nghe có vẻ giống nhau, nhưng hành vi lại khác biệt:
DELETE: Xóa các hàng khỏi một bảng dựa trên điều kiện. Có thể hoàn tác nếu ở trong một giao dịch. Ví dụ:
DELETE FROM employees WHERE department_id = 5;
TRUNCATE: Xóa mọi hàng trong một bảng, nhưng giữ nguyên cấu trúc bảng. Nhanh hơn DELETE và không thể hoàn tác. Ví dụ:
TRUNCATE TABLE employees;
DROP: Loại bỏ hoàn toàn cấu trúc và dữ liệu của bảng, cùng mọi phụ thuộc như chỉ mục. Ví dụ:
DROP TABLE employees;
9. Làm thế nào để tạo và sửa đổi một bảng trong MySQL? Hãy đưa ví dụ.
Để tạo bảng, bạn có thể dùng câu lệnh CREATE TABLE, và để sửa đổi thường dùng ALTER TABLE. Ví dụ:
Tạo bảng:
CREATE TABLE employees (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50), department VARCHAR(50));
Sửa để thêm cột:
ALTER TABLE employees ADD COLUMN salary DECIMAL(10, 2);
10. Bảng tạm (temporary table) trong SQL là gì?
Bảng tạm chỉ tồn tại trong phiên làm việc cơ sở dữ liệu hiện tại. Khi đóng phiên, bảng sẽ bị xóa. Loại bảng này có thể lưu tạm kết quả trung gian. Ta có thể dùng để thử nghiệm, lọc hoặc chuẩn bị dữ liệu trước khi chèn vào bảng vĩnh viễn.
Ví dụ:
CREATE TEMPORARY TABLE temp_employees (
id INT,
name VARCHAR(50)
);
INSERT INTO temp_employees VALUES (1, 'John Doe');
SELECT * FROM temp_employees;
11. Truy vấn con (subquery) trong MySQL là gì? Giải thích bằng ví dụ.
Truy vấn con (còn gọi là truy vấn lồng) được lồng bên trong một truy vấn khác. Nó chia nhỏ các thao tác cơ sở dữ liệu phức tạp thành các bước dễ quản lý hơn. Ví dụ, bạn có thể tạo subquery để tìm nhân viên có thu nhập trên mức trung bình:
SELECT first_name, last_name, salary
FROM employees
WHERE salary > (
SELECT AVG(salary)
FROM employees
);
Giải thích:
-
Truy vấn trong
SELECT AVG(salary) FROM employeestính mức lương trung bình trước. -
Truy vấn ngoài sau đó dùng mức trung bình này để tìm các nhân viên có thu nhập cao hơn.
12. Bạn sẽ dùng câu lệnh INSERT trong MySQL để thêm dữ liệu vào bảng như thế nào? Có lưu ý thực hành tốt nào không?
Ta có thể dùng câu lệnh INSERT để thêm dữ liệu vào bảng. Cú pháp cơ bản:
INSERT INTO table_name (column1, column2, ...)
VALUES (value1, value2, ...);
Một vài thực hành tốt khi dùng INSERT
-
Liệt kê rõ ràng các cột. Điều này giúp mã rõ ràng hơn và tránh lỗi nếu cấu trúc bảng thay đổi sau này.
-
Với các cột
AUTO_INCREMENTnhư ID, bỏ qua chúng trong câu lệnhINSERT. MySQL sẽ tự xử lý để tránh trùng ID. -
Nhất quán về dấu nháy chuỗi. Cá nhân tôi thích dùng nháy đơn, nhưng cả hai đều được.
-
Nếu chèn nhiều hàng, bạn có thể thực hiện trong một câu lệnh để hiệu năng tốt hơn.
13. Ý nghĩa của thuộc tính AUTO_INCREMENT trong MySQL là gì?
Thuộc tính AUTO_INCREMENT trong MySQL sinh ra các số duy nhất, tuần tự cho một cột, thường là khóa chính của bảng.
Ví dụ cách tạo bảng với cột AUTO_INCREMENT:
CREATE TABLE employees (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50),
department VARCHAR(50)
);
Và chèn các hàng vào đó:
INSERT INTO employees (name, department) VALUES ('John Doe', 'Sales');
INSERT INTO employees (name, department) VALUES ('Jane Smith', 'Marketing');
14. View trong MySQL là gì?
View là một truy vấn đã lưu, hoạt động như một bảng ảo. Với nó, ta có thể lấy một truy vấn phức tạp, đặt tên và dùng như một bảng cho các truy vấn sau. Nhờ vậy, bạn không phải gõ lại toàn bộ truy vấn mỗi lần.
Ví dụ, để đơn giản hóa việc truy vấn chi tiết nhân viên cùng tên phòng ban, bạn có thể tạo view:
CREATE VIEW employee_details AS
SELECT
e.id,
e.name,
d.department_name,
e.salary
FROM
employees e
JOIN
departments d ON e.department_id = d.department_id;
Giờ bạn có thể truy vấn view employee_details như một bảng:
SELECT * FROM employee_details;
Tuy nhiên, chúng ta không thể dùng view để chèn và cập nhật dữ liệu. Đa số view hỗ trợ chế độ chỉ đọc và ngăn người dùng truy cập trực tiếp cơ sở dữ liệu, tăng cường bảo mật dữ liệu. Đôi khi view có thể làm chậm truy vấn vì mỗi lần truy cập, truy vấn nền sẽ được chạy.
Câu Hỏi Phỏng Vấn MySQL Trình Độ Trung Cấp
Trong phần này, chúng ta sẽ đề cập đến các chủ đề mức trung cấp. Những câu hỏi này chủ yếu nhằm kiểm tra kiến thức của bạn về kiểu dữ liệu và cấu trúc trong MySQL.
15. Bảng có phiên bản hệ thống (system-versioned tables) là gì và hoạt động ra sao?
Bảng có phiên bản hệ thống duy trì toàn bộ lịch sử các thay đổi được thực hiện trên một bảng. Vì chúng giữ các phiên bản trước của mỗi hàng, chúng ta có thể dùng để kiểm toán và khôi phục dữ liệu.
Chúng hoạt động bằng cách thêm hai cột phụ — StartTime và EndTime — để ghi lại thời điểm mỗi hàng còn hiệu lực. Khi chèn, cập nhật hoặc xóa dữ liệu, các mốc thời gian này sẽ được cập nhật:
-
Insert: Thêm một hàng mới với
StartTimeđặt bằng thời điểm hiện tại vàEndTimelà9999-12-31 23:59:59— giá trịDATETIMEtối đa của MySQL, dùng như một giá trị đặc biệt biểu thị 'hàng này đang còn hiệu lực' -
Update:
EndTimecủa hàng gốc được cập nhật thành thời điểm hiện tại để đánh dấu là không còn hiệu lực. Sau đó, một hàng mới với dữ liệu cập nhật được tạo, vớiStartTimelà thời điểm hiện tại vàEndTimelà "mãi mãi". -
Delete:
EndTimecủa hàng hiện có được cập nhật thành thời điểm hiện tại, cho biết hàng không còn hiệu lực.
Bằng cách dùng mệnh đề FOR SYSTEM_TIME của SQL, bạn có thể truy vấn bảng để xem trạng thái của nó tại một thời điểm cụ thể hoặc trong một khoảng thời gian. Ví dụ:
-
FOR SYSTEM_TIME AS OF '2024-01-01': Truy xuất trạng thái của bảng như vào ngày 1/1/2024. -
FOR SYSTEM_TIME BETWEEN '2024-01-01' AND '2024-12-31': Hiển thị tất cả các hàng còn hiệu lực trong khoảng thời gian này.
16. Giao dịch (transaction) trong MySQL là gì và bạn dùng chúng như thế nào?
Giao dịch là một tập thao tác được thực thi như một đơn vị. Chúng đảm bảo toàn vẹn dữ liệu bằng cách cho phép tất cả thao tác hoặc cùng thành công, hoặc cùng thất bại.
Ví dụ sử dụng:
START TRANSACTION;
UPDATE accounts SET balance = balance - 500 WHERE account_id = 1;
UPDATE accounts SET balance = balance + 500 WHERE account_id = 2;
COMMIT; -- Lưu thay đổi vĩnh viễn
-- hoặc
ROLLBACK; -- Hoàn tác thay đổi
17. Ràng buộc mặc định (default constraint) trong MySQL là gì? Làm sao đặt giá trị mặc định cho một cột?
Ràng buộc mặc định trong MySQL gán một giá trị mặc định cho cột khi không cung cấp giá trị tường minh trong quá trình INSERT. Điều này đảm bảo cột hợp lệ ngay cả khi người dùng bỏ qua khi nhập dữ liệu.
Cách tạo bảng với giá trị mặc định:
CREATE TABLE employees (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50),
status VARCHAR(10) DEFAULT 'active'
);
Sau đó, bạn có thể chèn một hàng mà không chỉ định status:
INSERT INTO employees (name) VALUES ('John Doe');
Cách làm này giúp giảm khả năng xuất hiện NULL hoặc dữ liệu không hợp lệ ở các cột quan trọng và đơn giản hóa truy vấn bằng cách loại bỏ nhu cầu xử lý tường minh các trường hợp mặc định.
|
Field |
Type |
Null |
Key |
Default |
Extra |
|
id |
INT |
NO |
PRI |
NULL |
AUTO_INCREMENT |
|
name |
VARCHAR(50) |
YES |
NULL |
||
|
status |
VARCHAR(10) |
YES |
active |
Lệnh này hữu ích vì:
- Giúp nhà phát triển hiểu lược đồ bảng trước khi viết truy vấn.
- Có thể dùng để gỡ lỗi, đặc biệt khi làm việc với các cơ sở dữ liệu lạ.
- Nhanh chóng xác định các ràng buộc như khóa chính hoặc giá trị mặc định.
18. Sự khác nhau giữa CHAR và VARCHAR trong MySQL?
Cả hai đều lưu dữ liệu chuỗi, nhưng cách xử lý lưu trữ khác nhau:
-
CHAR(n)luôn lưu chính xácnký tự, đệm khoảng trắng nếu giá trị ngắn hơn. Đây là độ dài cố định, giúp nhanh hơn đôi chút cho các cột mà mọi giá trị có cùng độ dài, như mã quốc gia hoặc cờ trạng thái. -
VARCHAR(n)chỉ lưu số ký tự thực tế, tối đan. Nó dùng ít bộ nhớ hơn cho dữ liệu có độ dài biến thiên nhưng có chút chi phí để theo dõi độ dài.
CREATE TABLE example (
country_code CHAR(2), -- Always 2 chars, e.g. 'US', 'UK'
email VARCHAR(255) -- Variable length up to 255 chars
);
Nguyên tắc chung: dùng CHAR cho giá trị cố định độ dài, VARCHAR cho các trường hợp còn lại.
19. Bạn sẽ dùng các hàm chuỗi trong SQL để xử lý văn bản như thế nào?
Có nhiều hàm chuỗi trong SQL làm việc với tên và dữ liệu văn bản khác. Ví dụ:
-
Hàm
LENGTH()hiển thị số ký tự trong một tên. -
UPPER()vàLOWER()chuyển văn bản thành chữ hoa hoặc chữ thường. -
CONCAT()nối họ và tên thành một cột. -
SUBSTRING()trích xuất phần cụ thể của văn bản. Ví dụ, ta có thể dùng để tách tháng từ ngày sinh.
Ví dụ truy vấn:
SELECT
UPPER(first_name) AS upper_name,
CONCAT(first_name, ' ', last_name) AS full_name,
SUBSTRING(birthdate, 6, 2) AS birth_month,
TRIM(last_name) AS trimmed_last_name,
REPLACE(first_name, 'a', '@') AS replaced_name
FROM employees;
Truy vấn này:
-
Chuyển tên thành chữ hoa.
-
Kết hợp họ và tên thành tên đầy đủ.
-
Tách tháng sinh từ cột
birthdate. -
Loại bỏ khoảng trắng ở họ.
-
Thay mọi ký tự "a" bằng "@" trong tên.
20. Bạn sẽ cập nhật một hàng cụ thể trong cơ sở dữ liệu bằng SQL như thế nào?
Bạn có thể dùng câu lệnh UPDATE và mệnh đề WHERE để xác định bản ghi muốn thay đổi.
Ví dụ, nếu bạn muốn cập nhật thể loại của phim “Inception” năm 2010 sang “Sci-fi,” bạn có thể dùng truy vấn sau:
UPDATE movies
SET genre = 'Sci-Fi'
WHERE movie_title = 'Inception' AND year = 2010;
Ở đây, UPDATE movies chỉ định bảng cần cập nhật, và mệnh đề WHERE nhắm đến hàng có tiêu đề “Inception” và năm “2010”.
Câu Hỏi Phỏng Vấn MySQL Nâng Cao
Các câu hỏi nâng cao kiểm tra khả năng xử lý các kịch bản MySQL phức tạp và cho nhà tuyển dụng cái nhìn về cách bạn ra quyết định.
21. Trigger trong MySQL là gì? Bạn triển khai như thế nào?
Trong MySQL, trigger là một tập hành động chạy khi có sự kiện cơ sở dữ liệu xảy ra. Trigger có thể được cấu hình để thực thi trước hoặc sau các sự kiện như INSERT, UPDATE hoặc DELETE.
Ví dụ, giả sử có bảng orders nơi các đơn hàng mới được thêm vào. Ta có thể tạo một trigger ghi log mọi đơn hàng mới vào bảng order_history:
CREATE TRIGGER after_order_insert
AFTER INSERT ON orders
FOR EACH ROW
BEGIN
INSERT INTO order_history (order_id, action, timestamp)
VALUES (NEW.order_id, 'inserted', NOW());
END;
Sau khi trigger chạy, bảng order_history được cập nhật tự động:
|
history_id |
order_id |
action |
timestamp |
|
1 |
1 |
inserted |
2024-12-24 10:00:00 |
|
2 |
2 |
inserted |
2024-12-24 11:00:00 |
22. Tại sao thêm chỉ mục lại giúp truy vấn SQL nhanh hơn?
Nếu không có chỉ mục, cơ sở dữ liệu sẽ phải quét từng hàng để tìm mục nhập cụ thể. Chỉ mục hoạt động như một bảng mục lục, giúp cơ sở dữ liệu truy cập các hàng liên quan. Vì vậy, thêm chỉ mục rút ngắn thời gian tìm kiếm và giúp truy vấn chạy nhanh hơn.
Chỉ mục thường được triển khai bằng các cấu trúc dữ liệu như B-tree hoặc bảng băm, cho phép cơ sở dữ liệu thực hiện tìm kiếm, tra cứu và quét theo phạm vi hiệu quả.
Ví dụ cách tạo chỉ mục:
-- Without an index:
SELECT * FROM employees WHERE last_name = 'Smith';
-- Adding an index on the last_name column:
CREATE INDEX idx_last_name ON employees(last_name);
-- With the index, the database can quickly locate rows with 'Smith' in the last_name column.
Chỉ mục cũng có một số nhược điểm, ví dụ:
-
Ghi chậm hơn:
INSERT,UPDATEvàDELETE operations are slower because the index must be updated each time data changes. -
Chi phí lưu trữ: Chỉ mục yêu cầu thêm dung lượng lưu trữ.
23. Ta dùng kiểu dữ liệu gì cho cân nặng và giá sản phẩm trong bảng SQL, và vì sao?
Với cân nặng, DECIMAL thường là lựa chọn an toàn hơn. Dù FLOAT và REAL có thể lưu số thập phân, chúng dùng số học dấu phẩy động, có thể gây lỗi làm tròn nhỏ.
Với cân nặng sản phẩm nơi độ chính xác quan trọng (ví dụ: tính phí vận chuyển, tồn kho), DECIMAL(8, 3) cho phép bạn kiểm soát chính xác với 3 chữ số thập phân và không gặp vấn đề làm tròn. FLOAT chỉ chấp nhận khi sai số nhỏ là có thể chấp nhận.
24. Làm thế nào để tìm các hàng trùng lặp trong SQL bằng hàm cửa sổ (window function)?
Cách tìm trùng lặp bằng hàm ROW_NUMBER() như sau:
WITH DuplicateCheck AS (
SELECT product_name,
category,
ROW_NUMBER() OVER(
PARTITION BY product_name, category
ORDER BY id
) AS row_num
FROM sales
)
SELECT *
FROM DuplicateCheck
WHERE row_num > 1;
Giải thích cách hoạt động:
1. ROW_NUMBER() gán số thứ tự cho mỗi hàng trong kết quả.
2. PARTITION BY nhóm các hàng theo product_name và category.
3. Trong mỗi nhóm, các hàng được đánh số bắt đầu từ 1.
4. Bất kỳ row_num lớn hơn 1 biểu thị là trùng lặp.
Ví dụ, nếu ta có các bản ghi:
- Sản phẩm A, Danh mục X, row_num = 1
- Sản phẩm A, Danh mục X, row_num = 2 (trùng)
- Sản phẩm B, Danh mục Y, row_num = 1
Truy vấn sẽ hiển thị hàng thứ hai vì row_num lớn hơn 1.
25. Làm thế nào để tạo và sử dụng stored procedure với tham số trong MySQL? Giải thích bằng ví dụ.
Ta có thể lưu và tái sử dụng các truy vấn phức tạp bằng stored procedure để giúp thao tác cơ sở dữ liệu hiệu quả và dễ bảo trì hơn. Hãy xem cách tạo và dùng chúng với tham số qua một ví dụ thực tế.
Giả sử ta có cơ sở dữ liệu sinh viên và muốn tạo procedure để lọc sinh viên theo tuổi. Cách làm:
Đầu tiên, tạo một stored procedure đơn giản nhận tham số tuổi:
CREATE PROCEDURE get_student_info(IN age INT)
BEGIN
SELECT * FROM student WHERE student.age = age;
END;
Để dùng procedure này, chỉ cần CALL với tuổi mong muốn:
CALL get_student_info(21);
Ta có thể làm procedure phức tạp hơn bằng cách dùng tham số đầu ra. Ví dụ, tạo procedure đếm số sinh viên ở độ tuổi cụ thể:
CREATE PROCEDURE count_students_by_age(IN age INT, OUT student_count INT)
BEGIN
SELECT COUNT(*) INTO student_count FROM students WHERE students.age = age;
END;
Để lấy kết quả từ procedure này:
SET @count = 0;
CALL count_students_by_age(21, @count);
SELECT @count AS total_students;
26. Tại sao toàn vẹn tham chiếu (referential integrity) lại quan trọng trong cơ sở dữ liệu?
Toàn vẹn tham chiếu giữ cho mối quan hệ giữa các bảng luôn chính xác. Khi ta tạo khóa ngoại, nó đảm bảo các giá trị trong một bảng khớp với giá trị duy nhất ở bảng được tham chiếu.
Ví dụ thực tế: Giả sử bạn quản lý cơ sở dữ liệu thương mại điện tử. Bạn có bảng Customers và bảng Orders. Mỗi đơn hàng phải thuộc về một khách hàng có thật. Toàn vẹn tham chiếu, được thực thi qua khóa ngoại, áp đặt mối quan hệ này bằng cách đảm bảo:
- Bạn không thể tạo đơn hàng cho khách hàng không tồn tại.
- Bạn không thể xóa khách hàng có đơn hàng hiện hữu (trừ khi bạn cấu hình cụ thể điều gì sẽ xảy ra với các đơn đó).
- Bạn không thể cập nhật ID khách hàng nếu khách đó đang có các đơn hàng.
Vì vậy khi bạn tạo ràng buộc khóa ngoại như sau:
ALTER TABLE Orders
ADD FOREIGN KEY (CustomerID) REFERENCES Customers(CustomerID);
Cơ sở dữ liệu sẽ tự động thực thi các quy tắc này:
-
Mỗi
CustomerIDtrong bảngOrdersphải tồn tại trong bảngCustomers. -
Những nỗ lực vi phạm các quy tắc này (như chèn
CustomerIDkhông hợp lệ) sẽ bị từ chối.
Điều này ngăn ngừa bất nhất dữ liệu có thể gây ra vấn đề nghiêm trọng, chẳng hạn các đơn hàng không thể truy ngược về khách hàng thực hoặc báo cáo bị thiếu thông tin khách hàng.
Câu Hỏi Phỏng Vấn MySQL cho Quản Trị Viên Cơ Sở Dữ Liệu
Nếu bạn ứng tuyển riêng cho vai trò quản trị cơ sở dữ liệu, dưới đây là một số câu hỏi mà nhà tuyển dụng có thể hỏi.
27. Tại sao một ứng dụng lớn lại dùng sharding cơ sở dữ liệu? Cũng hãy cho tôi biết các thách thức của nó.
Một ứng dụng lớn dùng sharding cơ sở dữ liệu để chia nhỏ dữ liệu lớn trên nhiều máy chủ. Mỗi phần (shard) chứa một phần nhỏ dữ liệu. Vì tải dữ liệu được phân tán, không cần phần cứng cao cấp. Dù tốc độ và khả năng mở rộng được cải thiện, nó cũng có vài thách thức:
- Một số truy vấn như join có thể không hoạt động, khiến quản lý dữ liệu phức tạp.
- Khi dữ liệu tăng, một số shard có thể bị quá tải, tạo điểm nóng làm chậm hiệu năng.
28. Giải thích vai trò của redo log trong khôi phục sau sự cố của MySQL.
Mỗi khi dữ liệu được sửa đổi trong MySQL, nó cần được ghi xuống đĩa. Tuy nhiên, ghi trực tiếp vào tệp dữ liệu thì chậm và rủi ro. Vì thế, trước khi MySQL sửa đổi bất kỳ tệp dữ liệu nào, nó ghi trước những gì sẽ làm vào redo log. Cách này an toàn hơn so với việc cập nhật tệp dữ liệu một cách rải rác.
Giả sử bạn cập nhật địa chỉ của một khách hàng:
- MySQL đầu tiên ghi thay đổi này vào redo log.
- Sau đó xác nhận giao dịch của bạn đã được commit.
- Cuối cùng, nó áp dụng thay đổi vào các tệp dữ liệu thực tế.
Khôi phục sau sự cố quan trọng nếu MySQL gặp sự cố sau bước 1 hoặc 2 nhưng trước bước 3. Khi MySQL khởi động lại, nó xem redo log và hoàn tất phần việc còn dang dở bằng cách phát lại các thay đổi đã ghi trong redo log. Điều này đảm bảo các giao dịch đã commit không bị mất, ngay cả khi MySQL sập vào thời điểm không thuận lợi.
29. Có những bộ máy lưu trữ (storage engine) nào trong MySQL và chúng khác nhau thế nào?
MySQL hỗ trợ nhiều bộ máy lưu trữ, mỗi loại tối ưu cho các trường hợp khác nhau. Dưới đây là so sánh các loại phổ biến:
| Storage Engine | Key Features | Best For |
|---|---|---|
| InnoDB | Mặc định. Tuân thủ ACID, khóa cấp hàng, giao dịch và khóa ngoại. | Thương mại điện tử, hệ thống tài chính, bất cứ thứ gì yêu cầu toàn vẹn dữ liệu. |
| MyISAM | Đọc nhanh, khóa cấp bảng. Không có giao dịch hoặc khóa ngoại. | Ứng dụng đọc nhiều nơi tốc độ quan trọng hơn toàn vẹn. |
| Memory | Dữ liệu lưu trong RAM. Cực nhanh nhưng mất khi khởi động lại. | Cache, quản lý phiên, dữ liệu tạm. |
| CSV | Lưu dữ liệu dưới dạng tệp CSV thuần. Không có chỉ mục. | Trao đổi dữ liệu giữa ứng dụng hoặc lưu trữ dạng tệp phẳng đơn giản. |
| Archive | Nén cao. Chỉ INSERT và SELECT. Không có chỉ mục. | Dữ liệu log hoặc bản ghi lịch sử ít được truy vấn. |
| NDB (Clustered) | Lưu trữ phân tán, khả dụng cao, chịu lỗi, hỗ trợ giao dịch. | Ứng dụng phân tán quy mô lớn cần hiệu năng thời gian thực. |
30. Bạn sẽ đặt bộ máy lưu trữ mặc định trong MySQL như thế nào?
Trước tiên, bạn có thể kiểm tra bộ máy lưu trữ mặc định hiện tại:
SHOW ENGINES;
InnoDB được khuyến nghị làm mặc định vì hỗ trợ các tính năng quan trọng như:
- Giao dịch tuân thủ ACID
- Ràng buộc khóa ngoại
- Khôi phục sau sự cố
- Khóa cấp hàng
Để tạm thời thay đổi bộ máy mặc định cho phiên hiện tại, bạn có thể dùng:
SET default_storage_engine = 'InnoDB';
Để thay đổi vĩnh viễn, bạn có thể sửa tệp cấu hình MySQL bằng cách thêm dòng sau dưới phần [mysqld]:
default-storage-engine = InnoDB
31. Bạn sẽ sửa chữa các bảng bị hỏng trong MySQL như thế nào?
Đầu tiên, bạn có thể kiểm tra tất cả cơ sở dữ liệu với lệnh:
mysqlcheck --check --all-databases -u root -p
Lệnh này sẽ quét tất cả các bảng và báo nếu có hỏng hóc. Sau đó, bạn có thể chạy truy vấn sau để sửa bảng:
mysqlcheck --repair database_name table_name -u root -p
Việc sửa có thể dẫn đến mất dữ liệu trong trường hợp hỏng nặng, vì vậy hãy chắc chắn sao lưu dữ liệu.
Câu Hỏi Phỏng Vấn MySQL Dựa Trên Tình Huống và Giải Quyết Vấn Đề
Những câu hỏi này đo lường kinh nghiệm của bạn với các tình huống phức tạp ngoài đời thực và khả năng giải quyết vấn đề.
32. Giải thích một tình huống bạn đã dùng subquery trong MySQL.
Bạn có thể trả lời như sau:
Tôi từng quản lý cơ sở dữ liệu của một cửa hàng thương mại điện tử trong công việc gần đây, nơi tôi phải chuẩn bị báo cáo sản phẩm. Mục tiêu là tìm các sản phẩm tạo ra doanh số trên mức trung bình, đòi hỏi dùng subquery để thực hiện phân tích nhiều bước.
Đây là truy vấn SQL tôi xây dựng để giải quyết:
SELECT
p.product_id,
p.product_name,
s.sales_amount
FROM products p
JOIN sales s ON p.product_id = s.product_id
WHERE s.sales_amount > (
SELECT AVG(sales_amount)
FROM sales
)
ORDER BY s.sales_amount DESC;
Đầu tiên, tôi xác định ngưỡng bằng cách tính doanh số trung bình trên tất cả sản phẩm. Để làm vậy, tôi dùng một subquery trong mệnh đề WHERE tính AVG(sales_amount) từ bảng sales. Subquery này đóng vai trò như ngưỡng động để đo hiệu suất của từng sản phẩm.
Truy vấn chính sau đó join bảng products và sales để lấy chi tiết sản phẩm liên quan, trong khi mệnh đề WHERE loại bỏ những sản phẩm có doanh số dưới mức trung bình đã tính.
Bằng cách cấu trúc truy vấn như vậy, tôi có thể xác định các sản phẩm hiệu suất cao chỉ trong một thao tác cơ sở dữ liệu thay vì chạy nhiều truy vấn riêng lẻ.
33. Bạn có thể giải thích một tình huống đã dùng các phép JOIN để kết hợp dữ liệu từ nhiều bảng?
Ví dụ trả lời:
Gần đây, tôi làm việc trong một dự án có hai bảng chính — một bảng chứa dữ liệu doanh số sản phẩm và một bảng chứa chi tiết sản phẩm. Nhiệm vụ của tôi là tạo báo cáo hiển thị sales, product name, category và price.
Để kết hợp dữ liệu liên quan, tôi dùng INNER JOIN trên cột chung product_id để liên kết giao dịch bán hàng với chi tiết sản phẩm:
SELECT
s.sales_date,
p.product_name,
p.category,
s.quantity_sold,
p.price
FROM
sales s
INNER JOIN
products p
ON
s.product_id = p.product_id;
Báo cáo cung cấp bức tranh rõ ràng về xu hướng doanh số, giúp các bên liên quan xác định danh mục sản phẩm nào hoạt động tốt và danh mục nào cần chú ý.
34. Bạn có kinh nghiệm với trigger không? Hãy giải thích cách bạn đã dùng chúng.
Ví dụ câu trả lời:
Có, tôi có nhiều kinh nghiệm với trigger cơ sở dữ liệu. Gần đây, tôi triển khai trigger AFTER UPDATE để kiểm toán thay đổi giá.
Cụ thể: Tôi tạo một trigger tự động ghi lại lịch sử giá bất cứ khi nào giá sản phẩm thay đổi. Đây là script SQL tôi phát triển:
CREATE TRIGGER tr_AuditPriceChanges
AFTER UPDATE ON Products
FOR EACH ROW
BEGIN
-- Only log if the price actually changed
IF OLD.UnitPrice <> NEW.UnitPrice THEN
INSERT INTO PriceAudit (
ProductID,
OldPrice,
NewPrice,
ChangedBy,
ChangeDate,
PercentageChange
)
VALUES (
NEW.ProductID,
OLD.UnitPrice,
NEW.UnitPrice,
CURRENT_USER(),
NOW(),
ROUND(((NEW.UnitPrice - OLD.UnitPrice) / OLD.UnitPrice * 100), 2)
);
END IF;
END;
Điểm khiến giải pháp này hiệu quả:
- Chỉ kích hoạt khi thực sự có thay đổi giá.
- Ghi nhận người thực hiện thay đổi bằng
SYSTEM_USER. - Tính toán phần trăm thay đổi phục vụ báo cáo.
- Bao gồm mệnh đề
WHEREđể loại bỏ các trường hợp không thay đổi phát sinh từ cập nhật các cột khác.
Tôi cũng đã thêm xử lý lỗi và logging khi phát hiện một số trường hợp biên với giá NULL.
Mẹo Chuẩn Bị Cho Phỏng Vấn MySQL
Nếu bạn mới bắt đầu sự nghiệp, dưới đây là vài mẹo giúp bạn vượt qua buổi phỏng vấn sắp tới:
Nắm vững các khái niệm cốt lõi của MySQL: Hãy học các kiến thức nền tảng về cơ sở dữ liệu như đánh dánh chỉ mục, giao dịch và bộ tối ưu truy vấn. Hiểu cách MySQL xử lý truy vấn và quản lý lưu trữ dữ liệu. Điều này giúp bạn viết truy vấn hiệu quả và giải thích giải pháp trong buổi phỏng vấn.
Thực hành trực tiếp: Cài đặt MySQL trên máy tính và luyện tập thường xuyên. Tạo các cơ sở dữ liệu thử nghiệm, viết các loại truy vấn khác nhau và thử tối ưu chúng. Thực hành thực tế là cách tốt nhất để hiểu cách mọi thứ vận hành và xây dựng sự tự tin khi phỏng vấn.
Để ôn luyện thêm, hãy tham khảo tài nguyên của DataCamp:
- Cho phần giới thiệu SQL: Khóa học Nhập môn SQL
- Cho phần luyện tập SQL: Áp dụng SQL vào các bài toán thực tế
Tìm hiểu về công cụ và tích hợp MySQL: Làm quen với MySQL Workbench hoặc công cụ khác để quản lý cơ sở dữ liệu và giám sát cơ bản. Bbạn cũng có thể khám phá cách MySQL làm việc với Python và các framework liên quan, cho thấy bạn có thể làm việc trong môi trường phát triển thực tế.
Kết Luận
Vậy là xong! Tôi đã trình bày 34 câu hỏi phỏng vấn MySQL hàng đầu để giúp bạn giành được công việc tiếp theo. Dù bạn ứng tuyển vị trí entry-level hay quản trị dữ liệu nâng cao, bạn cần nắm vững nền tảng MySQL, tối ưu truy vấn và quản trị cơ sở dữ liệu để nổi bật.
Để mở rộng kiến thức về các hệ quản trị cơ sở dữ liệu khác, hãy tham khảo các khóa học SQL của DataCamp.
Tôi là một chiến lược gia nội dung, yêu thích việc đơn giản hóa các chủ đề phức tạp. Tôi đã giúp các công ty như Splunk, Hackernoon và Tiiny Host tạo nội dung hấp dẫn và giàu thông tin cho khán giả của họ.
