CodeGym /Các khóa học /SQL SELF /Chỉ mục hóa dữ liệu JSONB: sử dụng chỉ mục GIN

Chỉ mục hóa dữ liệu JSONB: sử dụng chỉ mục GINBTREE

SQL SELF
Mức độ , Bài học
Có sẵn

Chỉ mục hóa trong PostgreSQL là một cách để tìm kiếm dữ liệu trong database nhanh hơn. Nếu dữ liệu trong bảng của bạn là những cuốn sách, thì chỉ mục giống như mục lục trong thư viện, giúp bạn tìm sách theo tên hoặc tác giả siêu lẹ. Với JSONB thì hơi lắt léo hơn chút, vì dữ liệu được lưu ở dạng cấu trúc, không phải từng dòng và cột riêng biệt.

Khi dữ liệu JSONB bắt đầu phình ra kiểu như "sách Harry Potter mà không có hình minh họa", việc tìm kiếm bên trong cấu trúc này có thể siêu chậm. Ví dụ, nếu bạn muốn tìm tất cả đơn hàng mà key "status" có giá trị là "delivered", PostgreSQL phải duyệt hết mọi bản ghi để tìm. Nghe giống kiểu việc mà bạn chẳng bao giờ muốn làm thủ công đúng không?

Và chỉ mục GIN với BTREE chính là những anh hùng đến cứu bạn khỏi cảnh chờ đợi dài cổ!

Các loại chỉ mục cho JSONB

GIN (Generalized Inverted Index)

Chỉ mục GIN được sinh ra để xử lý dữ liệu có cấu trúc như mảng và object, nên nó cực kỳ hợp với JSONB. Nó không index cả object mà index từng key và value bên trong. Nghĩa là với GIN, bạn có thể tìm bản ghi chứa key, value hoặc tổ hợp nào đó rất nhanh.

Hãy tưởng tượng một cột JSONB với dữ liệu như này:

{"name": "Alice", "age": 25, "city": "Berlin"}

Chỉ mục GIN sẽ tạo ra một cấu trúc bên trong, nơi các key "name", "age""city" được liên kết với giá trị của chúng. Nên khi bạn tìm "name": "Alice", PostgreSQL đã biết chỗ để tìm rồi – không phải chạy vòng quanh cả bảng nữa.

BTREE

Chỉ mục BTREE thì truyền thống hơn. Nó tạo ra một cấu trúc có thứ tự, giúp tìm kiếm dữ liệu theo giá trị cụ thể rất nhanh. Với JSONB, chỉ mục BTREE dùng tốt khi bạn tìm kiếm chính xác dữ liệu hoặc có key cố định (kiểu như bạn muốn so sánh nguyên giá trị JSONB luôn).

Nếu cột của bạn chứa object JSONB như này:

{"name": "Bob", "age": 30}

Chỉ mục BTREE sẽ hữu ích nếu bạn tìm bản ghi mà object phải giống y chang.

{"name": "Bob", "age": 30}

Tạo chỉ mục cho JSONB

Đầu tiên xem cách tạo chỉ mục GIN Tất cả những gì bạn cần là câu lệnh thần thánh CREATE INDEX. Nó sẽ như này:

-- Tạo chỉ mục GIN cho cột JSONB
CREATE INDEX idx_jsonb_data ON orders USING GIN (data);

Trong đó:

  • idx_jsonb_data — tên chỉ mục.
  • orders — tên bảng.
  • data — cột chứa dữ liệu JSONB.

Sau khi tạo chỉ mục này, các truy vấn tìm kiếm key hoặc value trong JSONB sẽ chạy nhanh hơn nhiều.

Giả sử bạn có bảng orders với cột data chứa JSONB:

id data
1 {"status": "pending", "total": 100}
2 {"status": "delivered", "total": 200}

Truy vấn không có chỉ mục:

-- Tìm tất cả đơn hàng có status là "delivered"
SELECT * FROM orders WHERE data @> '{"status": "delivered"}';

Nếu bảng to, truy vấn này có thể chạy lâu lắm. Nhưng với chỉ mục GIN thì nó sẽ nhanh hơn hẳn.

Cách tạo chỉ mục BTREE

Để tạo chỉ mục BTREE bạn cần đổi cách tiếp cận một chút. Thường thì để dùng BTREE với JSONB, bạn phải chỉ rõ là muốn index một phần nào đó, không phải cả object. Ví dụ:

-- Tạo chỉ mục BTREE cho một key cụ thể
CREATE INDEX idx_jsonb_total ON orders ((data->>'total'));

Lưu ý (data->>'total'). Nó lấy giá trị của key total từ object JSONB, và chính giá trị này sẽ được index. Giờ nếu bạn tìm đơn hàng có total = 100, PostgreSQL sẽ dùng chỉ mục này.

Ví dụ sử dụng với dữ liệu trên:

id data
1 {"status": "pending", "total": 100}
2 {"status": "delivered", "total": 200}

Truy vấn:

-- Tìm tất cả đơn hàng mà total = 100
SELECT * FROM orders WHERE data->>'total' = '100';

Với chỉ mục BTREE cho data->>'total', truy vấn này sẽ chạy nhanh hơn nhiều.

So sánh GINBTREE

Đặc điểm GIN BTREE
Cái gì được index? Key và value bên trong JSONB Đường dẫn hoặc giá trị chỉ định
Kịch bản dùng tốt nhất Tìm kiếm theo từng phần của object Tìm kiếm theo giá trị cụ thể
Hiệu năng tạo chỉ mục Chậm hơn Nhanh hơn
Hiệu năng tìm kiếm Nhanh hơn cho cấu trúc phức tạp Nhanh hơn cho giá trị cố định
Hỗ trợ operator @>, ?, `? ,?&`

Nếu bạn có cấu trúc JSONB phức tạp và hay dùng các operator như @> hoặc ?, hãy chọn GIN. Nếu bạn tìm kiếm giá trị hoặc key cụ thể, cố định, BTREE có thể là lựa chọn ngon hơn.

Bẫy và lỗi phổ biến khi index JSONB

Làm việc với chỉ mục JSONB rất mạnh, nhưng cũng có vài cái bẫy bạn nên chú ý.

  1. Thiếu chỉ mục ở chỗ cần thiết. Nếu bạn hay dùng dữ liệu JSONB trong filter (WHERE), mà không tạo chỉ mục, truy vấn sẽ rất chậm.
  2. Index quá nhiều. Nếu bạn tạo chỉ mục cho mọi key có thể trong JSONB, việc insert và update sẽ chậm đi đáng kể.
  3. Chọn sai loại chỉ mục. Nếu truy vấn của bạn phức tạp, dùng operator kiểu @> hoặc ?, mà lại tạo chỉ mục BTREE, thì cũng chẳng nhanh hơn đâu.
  4. Không biết về đường dẫn. Nếu bạn hay truy cập giá trị lồng nhau, mà không tạo chỉ mục cho đường dẫn cụ thể (ví dụ data->>'some_key'), truy vấn vẫn sẽ chậm thôi.

Tóm lại: khi nào dùng chỉ mục nào

  • Dùng GIN nếu bạn có mảng hoặc object phức tạp, hay tìm kiếm theo key và value.
  • Dùng BTREE nếu bạn tìm kiếm chính xác hoặc hay truy cập một key cụ thể.
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION