Hôm nay tụi mình sẽ kết thúc chuyến phiêu lưu thú vị về làm việc với mảng trong PostgreSQL. Chủ đề hôm nay là những lỗi thường gặp mà bạn có thể đụng phải, và quan trọng nhất là làm sao để né chúng. Nếu bạn từng nghĩ kiểu "cái mảng này lại làm trò gì kỳ cục nữa rồi", thì bài này dành cho bạn đó. Cùng tìm hiểu nha.
Lỗi khi tạo mảng: vấn đề với kiểu dữ liệu bên trong mảng
Khi bạn tạo mảng trong PostgreSQL, nhớ là tất cả phần tử trong mảng phải cùng kiểu dữ liệu. Ví dụ nè:
SELECT ARRAY[1, 2, 'ba'];
-- Lỗi: trong mảng các phần tử phải cùng kiểu
PostgreSQL sẽ không cho phép bạn trộn số và chuỗi trong cùng một mảng đâu. Nếu bạn thật sự cần như vậy, hãy dùng chuyển đổi kiểu:
SELECT ARRAY[1::TEXT, 2::TEXT, 'ba'];
-- Giờ mảng toàn là chuỗi
Lỗi khi dùng ARRAY[] với các kiểu dữ liệu khác nhau
Mặc định PostgreSQL sẽ cố đoán kiểu mảng dựa trên nội dung của nó. Nếu bạn đưa vào dữ liệu không rõ ràng, chuẩn bị tinh thần gặp lỗi nha:
SELECT ARRAY[1, NULL];
-- Lỗi: PostgreSQL không biết phải hiểu NULL kiểu gì
Để giải quyết, hãy chỉ rõ kiểu dữ liệu luôn:
SELECT ARRAY[1, NULL]::INTEGER[];
-- Mọi thứ chạy ngon lành
Lỗi khi truy xuất dữ liệu: vấn đề với chỉ số mảng
Nếu bạn quen code Python hay JavaScript, nơi chỉ số mảng bắt đầu từ 0, thì PostgreSQL sẽ làm bạn bất ngờ đó. Ở đây, mảng được đánh chỉ số bắt đầu từ 1 nha.
SELECT ARRAY[10, 20, 30][0];
-- Lỗi: chỉ số phải bắt đầu từ 1
Truy vấn đúng nè:
SELECT ARRAY[10, 20, 30][1];
-- Kết quả: 10
Lỗi khi dùng hàm để truy xuất
Các hàm như unnest() có thể gây rối nếu bạn không để ý là nó sẽ "bung" mảng ra thành từng dòng:
CREATE TEMP TABLE example (
id SERIAL PRIMARY KEY,
tags TEXT[]
);
INSERT INTO example (tags) VALUES (ARRAY['tag1', 'tag2']), (ARRAY['tag3']);
SELECT unnest(tags) FROM example;
-- Kết quả:
-- tag1
-- tag2
-- tag3
Nếu bạn cần giữ lại ngữ cảnh dòng (ví dụ id), hãy thêm nó vào truy vấn luôn:
SELECT id, unnest(tags) AS tag FROM example;
-- Kết quả:
-- id | tag
-- 1 | tag1
-- 1 | tag2
-- 2 | tag3
Lỗi khi lọc và so sánh mảng
- Dùng sai các toán tử
@>,<@,&&
Những toán tử này dùng cho các mục đích riêng biệt:
@>kiểm tra xem mảng này có chứa mảng kia không.<@kiểm tra xem mảng này có nằm trong mảng khác không.&&kiểm tra hai mảng có giao nhau không.
Lỗi sẽ xảy ra nếu bạn dùng sai mục đích:
SELECT ARRAY[1, 2, 3] @> 2;
-- Lỗi: toán tử @> chỉ dùng cho mảng
Làm đúng nè:
SELECT ARRAY[1, 2, 3] @> ARRAY[2];
-- Kết quả: true
- Vấn đề hiệu năng khi không có index
Nếu bạn dùng các toán tử cho mảng nhiều mà thấy truy vấn chậm, khả năng cao là bạn quên tạo index rồi. Đây là ví dụ tạo index cho mảng:
CREATE INDEX idx_tags ON example USING GIN (tags);
Giờ các truy vấn với @> và && sẽ chạy nhanh hơn nhiều.
Lỗi khi sửa đổi mảng
- Xoá và thêm giá trị
Các hàm array_remove() và array_append() không thay đổi mảng "tại chỗ", mà trả về mảng mới. Nếu bạn nghĩ mảng gốc sẽ thay đổi thì nhầm rồi nha:
UPDATE example
SET tags = array_remove(tags, 'tag1');
-- Giờ mảng đã được cập nhật
Nếu bạn quên không ghi SET tags =, SQL vẫn chạy nhưng mảng không đổi đâu.
- Bị trùng dữ liệu khi dùng
array_append()
Hàm array_append() không kiểm tra phần tử đã có chưa. Điều này có thể làm bị trùng:
SELECT array_append(ARRAY['tag1', 'tag2'], 'tag1');
-- Kết quả: {tag1, tag2, tag1}
Nếu muốn tránh trùng, hãy lọc trước:
SELECT array_remove(array_append(ARRAY['tag1', 'tag2'], 'tag1'), 'tag1') || 'tag1';
-- Kết quả: {tag1, tag2}
Mẹo để tránh lỗi
Để tránh các lỗi trên khi làm việc với mảng:
- Kiểm tra kiểu dữ liệu. Luôn chỉ rõ kiểu mảng nếu có gì không rõ ràng.
- Cẩn thận với chỉ số. Nhớ là mảng trong PostgreSQL bắt đầu từ 1 nha.
- Tối ưu truy vấn với mảng. Dùng index để tăng tốc so sánh và lọc.
- Test với dữ liệu nhỏ. Nếu truy vấn mảng chạy chậm, thử với ít dữ liệu để tìm chỗ nghẽn.
- Tránh trùng lặp. Kiểm tra kỹ khi thêm phần tử vào mảng nếu không muốn bị lặp.
Mảng trong PostgreSQL, giống như vũ khí mạnh, cần được tôn trọng và dùng cẩn thận. Làm theo mấy mẹo này thì mảng sẽ không còn làm bạn mất ngủ nữa đâu (gần như vậy thôi). Chúc bạn thiết kế và tối ưu database thành công nha!
GO TO FULL VERSION