Relational Database – Vài trò không được dạy ở trường (P2)

Nối tiếp phần trước, dưới đây là vài trò con bò khác mình muốn chia sẻ với các bạn trong quá trình tìm hiểu và làm việc với relational database.

Cẩn thận với kích thước đầu vào

Khi lựa chọn kiểu dữ liệu, đặc biệt là giới hạn của chuỗi hay số, hãy luôn cân nhắc đến kích thước tối đa mà giá trị có thể có. Nếu bạn cần lưu dữ liệu là giá trị tiền Việt Nam lên đến hàng nghìn tỉ, hãy chọn kiểu dữ liệu BIGINT (nếu có thể, hãy kèm theo đánh dấu UNSIGNED để gấp đôi khả năng lưu trữ nếu dữ liệu đầu vào đảm bảo không âm).

Youtube trước đây đã thiết kế kiểu dữ liệu đếm view các video là SIGNED INT, vào năm 2012, với sự bùng nổ của hit Gangnam Style (PSY) đã khiến lượt view vượt quá giới hạn bộ đếm, hay nói cách khác là vượt quá maximum value của kiểu SIGNED INT (tương đương gần 2.15 tỉ), và trường hợp hi hữu đã xảy ra: bộ đếm đã thực hiện đếm ngược lại từ minimum value của kiểu signed INT dẫn đến bug huyền thoại bên dưới.

Nhưng giờ Google đã update thành signed BIGINT rồi nhé

Tương tự với kiểu dữ liệu dạng chuỗi, trước đây ta thường quy định kích thước tối đa cho chuỗi nhập vào, nhưng nếu đối với những trang hỗ trợ viết blog, các bài báo… để render một lượng tag html cực lớn với nhiều hình ảnh, format cho những bài viết không xác định được độ dài có thể lên đến hàng chục nghìn hay hàng trăm nghìn kí tự – thì hiện nay các engine database cũng đã cung cấp một số kiểu dữ liệu giải quyết vấn đề này như TEXT hay NVARCHAR(MAX).

Biết trước những giới hạn của kiểu dữ liệu đầu vào giúp ta thuận lợi hơn trong việc thiết kế database và cũng tránh đi những trường hợp sinh ra những lỗi không mong muốn, nếu chỉ đơn giản là bộ đếm view youtube thì chỉ ảnh hưởng mặt hiển thị, nhưng nếu nó là thông số game, xử lí về tiền bạc, công văn,… đang đạt giá trị cực đại lại chuyển sang cực tiểu, thì đó là cả một vấn đề rất lớn.

Liệu cơm gắp mắm với select

Dữ liệu bạn SELECT càng nhiều, càng tốn thời gian để lấy, thời gian để chuyển đến backend, thời gian để chuyển từ backend lên frontend, và nếu frontend không dùng những dữ liệu dư thừa đó, thì đó thật sự phí phạm về mặt xử lí.

Trong một số dự án cần tối ưu về mặt tốc độ xử lí dữ liệu, thay vì thông qua một ORM, các dev sẽ dùng native query ở backend hoặc thậm chí gọi các store procedure ở tầng database cho các câu lệnh select để chọn ra các column cần thiết cũng như cải thiện performance.

Hoặc trong một số thiết kế, các bảng cũng có thể liên kết với nhau qua quan hệ 1-1 như bảng usersuser_credentials để phân biệt giữa thông tin người dùng và thông tin đăng nhập, tránh việc SELECT quá nhiều cột cũng như làm lộ một số thông tin không mong muốn.

Như việc bạn muốn để lương nhân viên ở một bảng riêng

Bạn không cần bảng tham số đến thế

Các quy định như số giỏ hàng tối đa trong ứng dụng mua sắm ở các cửa hàng khác nhau, domain cho từng môi trường (dev – stage – production) hay các feature flag để tích hợp chức năng mới không nhất thiết phải lưu trong bảng database, hay ngày trước mình được dạy là các bảng tham số.

Đặc biệt trong các dự án cần có sự tham gia kiểm soát hay kiểm thử của các vị trí khác vai trò developer, việc cần phải thay đổi liên tục các tham số đôi khi lại dẫn đến những kết quả không mong muốn, cũng như phải thực hiện thêm việc cấp thêm quyền truy cập, phân quyền và thao tác với database.

Bạn không cần phải lưu đống như thế này vào database đâu

Các hạ tầng backend cũng như deployment nay đã phát triển và hỗ trợ khả năng đọc file theo từng môi trường khác nhau, việc quy định các tham số có thể được để trong các file config hay environment sẽ thuận tiện hơn trong việc thiết kế, theo dõi và cập nhật cho mọi vị trí trong dự án.

Hãy tôn vinh sự duy nhất của record

Nếu table của bạn có một column sẽ mang giá trị khác nhau cho từng record, như bảng user thì có user_idusername sẽ là duy nhất, việc đánh dấu UNIQUE constrain hay UNIQUE index cho cột username sẽ giúp cải thiện performance rất lớn (ở đây ta xem user_id là primary key, lẽ dĩ nhiên sẽ luôn kèm theo key UNIQUE).

Hãy tôn vinh các unique record bằng việc gắn UNIQUE constraint/index

Cụ thể như câu lệnh có phần WHERE username = 'abc' AND other_field = 'xxx', nếu column username đã được đánh dấu là unique, engine database sẽ ưu tiên tìm theo điều kiện username trước và sẽ dừng lại ngay khi tìm thấy record đầu tiên và kiểm tra các điều kiện còn lại tại đúng record đó.

Hà Nội không vội cùng database

Một đơn hàng được sale khủng với số lượng có hạn, bạn vừa chuyển tiền cho đứa bạn đang cần cứu trợ,… có thể dễ dàng để xử lí, nhưng nếu đó là hàng trăm nghìn đơn mỗi ngày trên các sàn thương mại điện tử hay hàng nghìn đợt chuyển khoản liên tục từ một lần kêu gọi từ thiện của nghệ sĩ nào đó, thì việc tối giản xử lí cũng như performance là bắt buộc.

Hai trường hợp kể trên đều sẽ có một bước thực hiện gửi mail thông báo về cho người mua hàng/chuyển khoản, nhưng thao tác để xử lí gửi mail rất cồng kềnh – thiết lập connection, kiểm tra hợp lệ, soạn và mapping data vào nội dung từ template có sẵn và gửi đi. Quá trình này sẽ tốn rất nhiều thời gian xử lí cũng như cũng dễ sinh ra lỗi, nhưng ưu tiên lớn nhất của người dùng bấy giờ là cần được ghi nhận đơn hàng đã chốt thành công cũng như tiền đã được chuyển đi.

Vậy việc gửi mail thông tin có thể được xử lí sau, trong trường hợp này, ta có thể lưu trữ request tại database đánh dấu cho thao tác gửi mail bằng việc tạo một record kèm theo trạng thái chờ gửi đi và tiếp tục với các thao tác xử lí khác. Sau đó sẽ thực hiện chạy job quét qua các record đó và thực hiện gửi mail, và vì đã được lưu trong database, tác vụ cũng có thể thực hiện retry lại nhiều lần trong trường hợp xảy ra lỗi thông qua việc quản lí field status hay state trong record.

Đây cũng là ứng dụng của database trong việc xử lí những thao tác không khẩn cấp và luôn đảm bảo luôn có nguồn data có thể thực hiện cho việc retry, đồng thời giảm thiểu xử lí cho các thao tác cần tối ưu về performance (các bạn có thể nghiên cứu về event driven architect cho phương pháp này).

Ví dụ khác về xử lí đặt xe theo từng trạng thái ứng dụng event-driven

Những lựa chọn khác để lưu trữ

Relational database từng được xem như chuẩn mực không thể thiếu trong việc thiết kế cơ sở dữ liệu, nhưng với việc cập nhật liên tục của công nghệ cũng như yêu cầu lưu trữ khác nhau, nay đã có nhiều thiết kế khác để chứa data của bạn như key-value store, document store, column-oriented database hay graph database (hay các công nghệ thuộc nhóm NoSQL).

Thế giới database hiện tại rất phong phú

Mỗi công nghệ khác nhau sẽ ứng dụng cho những yêu cầu và bài toán khác nhau, đôi khi relational database lại không phải là giải pháp tối ưu cho tất cả vấn đề về lưu trữ, vì vậy cũng đừng cứng nhắc trong việc luôn áp đặt cơ sở dữ liệu quan hệ nhé.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s