CodeGym /Các khóa học /SQL SELF /Ví dụ về denormalization dữ liệu và hậu quả của nó

Ví dụ về denormalization dữ liệu và hậu quả của nó

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

Normalization giải quyết một số vấn đề, nhưng đôi khi lại tạo ra vấn đề khác, nhất là khi nói về performance. Hôm nay tụi mình sẽ mở cánh cửa cho bạn vào thế giới (đôi khi tối, đôi khi sáng) của denormalization. Đúng rồi, bạn có thể phá vỡ các quy tắc normalization... nhưng nhớ là phải dùng não nha!

Denormalization là quá trình ngược lại với normalization. Nếu normalization chia nhỏ bảng thành các entity logic riêng biệt để giảm dư thừa, thì denormalization lại gom dữ liệu lại để tăng performance. Denormalization thường được dùng khi hệ thống chịu tải cao và các truy vấn phức tạp với nhiều bảng join bắt đầu làm chậm hệ thống.

Có thể nói, denormalization là sự thỏa hiệp giữa độ sạch của dữ liệu và tốc độ thực thi truy vấn.

Khi nào nên dùng denormalization?

Giống như bất kỳ công cụ nào, quan trọng là phải biết khi nào denormalization là hợp lý. Nó được dùng trong các trường hợp sau:

  1. Các truy vấn thường dùng bị chậm. Khi hệ thống chịu tải lớn và thường xuyên chạy các truy vấn giống nhau (ví dụ như báo cáo tổng hợp, aggregate), việc join nhiều bảng có thể tốn rất nhiều thời gian. Denormalization giúp giảm số lượng join kiểu này.

  2. Nhiệm vụ phân tích và thống kê. Trong các hệ thống phân tích (ví dụ BI — Business Intelligence), thường cần phân tích dữ liệu khủng. Lúc này denormalization giúp xử lý nhanh hơn nhờ dữ liệu đã được "chuẩn bị sẵn".

  3. Truy vấn phức tạp. Nếu để chạy một truy vấn mà phải join năm, mười hay thậm chí nhiều bảng hơn, database sẽ bị chậm hẳn. Denormalization giúp đơn giản hóa cấu trúc truy vấn.

  4. Số lượng join vượt quá mức hợp lý. Nếu bạn có truy vấn join tới 25 bảng trong JOIN, chắc là đã đến lúc xem lại cách thiết kế rồi đó.

Ví dụ về denormalization

Ví dụ 1: Cửa hàng online. Trong một database đã normalization của cửa hàng online, bạn có thể có các bảng như sau:

  1. customers — dữ liệu về khách hàng.
  2. orders — thông tin về đơn hàng.
  3. products — dữ liệu về sản phẩm.
  4. order_items — sản phẩm trong đơn hàng.

Truy vấn để lấy thông tin có thể như sau:

SELECT
    c.customer_name,
    o.order_date,
    p.product_name,
    oi.quantity
FROM 
    customers c
JOIN 
    orders o ON c.customer_id = o.customer_id
JOIN 
    order_items oi ON o.order_id = oi.order_id
JOIN 
    products p ON oi.product_id = p.product_id
WHERE 
    c.customer_id = 42;

Nhưng nếu cửa hàng online của bạn xử lý hàng trăm ngàn đơn mỗi ngày thì sao? Truy vấn này sẽ bị chậm vì quá nhiều join.

Giải pháp: denormalization.

Hãy tạo một bảng cho thông tin thường dùng:

CREATE TABLE order_summary AS
SELECT 
    c.customer_id,
    c.customer_name,
    o.order_id,
    o.order_date,
    p.product_id,
    p.product_name,
    oi.quantity
FROM 
    customers c
JOIN 
    orders o ON c.customer_id = o.customer_id
JOIN 
    order_items oi ON o.order_id = oi.order_id
JOIN 
    products p ON oi.product_id = p.product_id;

Bây giờ, khi cần lấy dữ liệu, chỉ cần query bảng order_summary thôi:

SELECT * FROM order_summary WHERE customer_id = 42;

Ví dụ 2: Hệ thống phân tích. Giả sử bạn làm việc với database cho một công ty bán vé sự kiện. Có các bảng:

  1. events — thông tin về sự kiện.
  2. sales — dữ liệu về bán vé.

Nếu analyst cần tạo báo cáo về doanh thu trung bình trên mỗi vé cho tất cả sự kiện, cấu trúc đã normalization bắt bạn phải chạy truy vấn aggregate mỗi lần:

SELECT
    e.event_name,
    AVG(s.price) AS avg_ticket_price
FROM 
    events e
JOIN 
    sales s ON e.event_id = s.event_id
GROUP BY 
    e.event_name;

Truy vấn này có thể rất chậm, nhất là khi mỗi sale chiếm hàng triệu dòng.

Giải pháp: denormalization. Tạo một bảng riêng với dữ liệu đã aggregate:

CREATE TABLE event_summary AS
SELECT 
    e.event_id,
    e.event_name,
    COUNT(s.sale_id) AS ticket_count,
    SUM(s.price) AS total_revenue,
    AVG(s.price) AS avg_ticket_price
FROM 
    events e
JOIN 
    sales s ON e.event_id = s.event_id
GROUP BY 
    e.event_id, e.event_name;

Bây giờ các báo cáo sẽ chạy nhanh hơn trên dữ liệu đã aggregate:

SELECT
    event_name, 
    avg_ticket_price 
FROM 
    event_summary;

Hậu quả của denormalization

Denormalization chắc chắn có thể tăng tốc truy vấn, nhưng nó không phải là cây đũa thần giải quyết mọi vấn đề đâu nha. Đây là những gì bạn có thể gặp phải nếu quyết định dùng nó.

Đầu tiên là trùng lặp dữ liệu. Khi cùng một thông tin được lưu ở nhiều chỗ, database sẽ phình to rất nhanh và việc quản lý sẽ khó hơn.

Thứ hai là việc update dữ liệu sẽ khó hơn. Hãy tưởng tượng bạn có dữ liệu khách hàng trong bảng customers, và còn một bản copy trong bảng order_summary. Nếu khách đổi tên hoặc địa chỉ, bạn phải nhớ update ở cả hai nơi. Quên một cái là lỗi liền, vì dữ liệu không còn khớp nữa.

Thứ ba là do dư thừa như vậy nên rất dễ bị rối và mắc lỗi. Giống như có nhiều version của cùng một tài liệu — đôi khi không biết cái nào mới là đúng.

Và cuối cùng, việc bảo trì và phát triển database kiểu này sẽ khó hơn. Bạn sẽ phải viết trigger hoặc script riêng để đảm bảo mọi bản copy dữ liệu luôn đồng bộ. Đó là thêm việc cho dev.

Nói chung, denormalization là một công cụ nên dùng một cách thông minh, hiểu rõ cả mặt lợi và hại của nó.

1
Khảo sát/đố vui
, cấp độ , bài học
Không có sẵn
Chuẩn hóa dữ liệu
Chuẩn hóa dữ liệu
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION