3. Các phương pháp tối ưu hóa cơ sở dữ liệu mức vật lý
3.5. Ví dụ về thiết kế file
Xét ví dụ sau: hệ thống quản lý quá trình đặt hàng của cửa hàng bao gồm: nhận đơn đặt hàng In phiếu giao hàng gồm 2 chứng từ sau:
Báo cáo đề tài nghiên cứu khoa học và công nghệ cấp trường 2019
ThS. Hoàng Ngọc Cảnh – TT. Công nghệ thông tin 43
Hình 15: Chứng từ phiếu giao hàng
Sau quá trình thiết kế logic ta được lược đồ CSDL quản lý đặt hàng bao gồm các quan hệ sau:
- KHACH(Ma_Khach, Ten_kh, DiaChi_kh)
- HANG(Ma_hang, Ten_hang, Mota_hang, Donvi) - DONHANG(So_Don, Ma_Khach, NgayDon)
- PHIEUGIAO(So_Phieu, Ma_Khach, Noi_Giao, Ngay_Giao) - DONGDON(So_Don, Ma_Hang, So_luongD)
- DONGPHIEUGIAO(So_Phieu, MaHang, So_luonggi, DonGia)
4. Các phương pháp tối ưu hóa cơ sở dữ liệu mức logic 4.1. Tối ưu tổ chức dữ liệu
Một số quy tắc giúp tối ưu trong tổ chức dữ liệu như sau:
- Xem xét tới bản chất của ứng dụng khai thác dữ liệu: Khi bắt đầu thiết kế CSDL, điều đầu tiên cần nghĩ tới là phân tích xem bản chất của ứng dụng cần thiết kế là thao tác (transaction) hay phân tích (analytical). Phần lớn người thiết kế mặc định áp dụng các quy tắc chuẩn hóa mà không hề suy nghĩ gì về bản chất của ứng dụng dẫn đến vấn đề sửa đổi và hiệu năng sau này. Với loại ứng dụng thao tác, người dùng cuối quan tâm tới CRUD (Create, Read, Update and Delete) nghĩa là tạo mới, đọc, cập nhật và xóa bản ghi nhiều hơn, tên thường gọi của loại CSDL này là OLTP (On-line transactional processing). Với loại phân tích, người dùng cuối quan tâm tới việc phân tích, báo cáo, dự báo nhiều hơn. Loại CSDL này có ít thao tác thêm mới và cập nhật. Yêu cầu chính của loại này là lấy dữ liệu và phân tích nhanh nhất có thể, loại CSDL này thường gọi là OLAP (On-line analytical processing). Nói cách khác, nếu thêm mới, cập nhật và xóa bản ghi là giao dịch chủ yếu thì cần thiết kế theo chuẩn hóa mức cao, ngược lại tạo CSDL không chuẩn hóa mức quá cao.
Báo cáo đề tài nghiên cứu khoa học và công nghệ cấp trường 2019
ThS. Hoàng Ngọc Cảnh – TT. Công nghệ thông tin 44
- Tránh chuẩn hóa yếu: Thực tế có những CSDL được thiết kế mà không áp dụng theo những quy tắc chuẩn hóa cơ bản nhất. Chúng ta phải biết rõ rằng: Mọi CSDL nên ít nhất được chuẩn hóa theo dạng 3NF vì đó là mô hình tốt nhất để thể hiện các thực thể dữ liệu và sẽ cân bằng được hiệu năng truy vấn và thêm-sửa-xóa bản ghi.
- Không cứng nhắc trong việc chống dư thừa dữ liệu nếu hiệu năng là yếu tố quan trọng: Không cần tuân thủ nghiêm ngặt quy tắc luôn phải chống dư thừa dữ liệu. Nếu hiệu năng là yêu cầu cấp thiết thì nên nghĩ đến vấn đề không chuẩn hóa. Với dữ liệu chuẩn hóa, bạn cần join nhiều bảng và với dữ liệu không chuẩn hóa, các thao tác join sẽ giảm đi và do đó làm tăng hiệu năng.
- Tránh ràng buộc yếu: Ràng buộc là một trong những yếu tố quan trọng nhất mà database engines đảm bảo cho dữ liệu được chất lượng tốt nhất. Nếu không có ràng buộc hoặc rất ít ràng buộc được thiết lập trong giai đoạn thiết kế, thì tính bảo toàn của dữ liệu sẽ phải dựa hoàn toàn vào phần logic nghiệp vụ, khiến dữ liệu dễ bị ảnh hưởng bởi những lỗi do con người gây ra.
- Tận dụng những tính năng của DB Engine: Database engine (DBE) là một công cụ xử lý dữ liệu mạnh mẽ giúp đơn giản hóa việc phát triển phần mềm cũng như đảm bảo thông tin luôn chính xác, an toàn và dễ sử dụng. Một DBE cung cấp những dịch vụ như: Views cho phép duyệt dữ liệu một cách nhanh chóng và hiệu quả, bỏ chuẩn hóa để truy vấn mà không làm mất độ chính xác của dữ liệu; Chỉ mục giúp tăng tốc truy vấn ở các bảng; Các hàm tập hợp giúp phân tích thông tin mà không cần lập trình quá phức tạp; Transactions: giúp bảo toàn dữ liệu khi có lỗi xảy ra; Locks giúp dữ dữ liệu được an toàn và chính xác khi transactions được thực thi; Thủ tục lưu trữ cung cấp tính năng lập trình để xử lý những công việc quản lý dữ liệu phức tạp; Hàm cho phép tính toán và chuyển đổi dữ liệu phức tạp; Ràng buộc giúp bảo toàn độ chính xác của dữ liệu và tránh lỗi; Triggers giúp tác vụ được thực hiện tự động khi có sự kiện xảy ra trên dữ liệu.
- Cân nhắc sử dụng khóa chính kết hợp: Đây là một điểm gây tranh cãi, bởi nhiều người thiết kế CSDL ngày này thường nói về việc sử dụng trường số nguyên ID được sinh tự động làm khóa chính thay vì khóa được tạo bởi việc kết hợp từ 2 trường trở lên. Tuy nhiên, đây dĩ nhiên chỉ là một convention, các DBE cho phép định nghĩa các khóa chính kết hợp, điều mà nhiều người thiếtt kế nghĩ là không tránh khỏi. Do đó, như sự dư thừa, có sử dụng khóa chính kết hợp hay không là tùy vào từng quyết định thiết kế. Nhưng nếu bảng dùng khóa chính kết hợp có hàng triệu bản ghi, dẫn đến chỉ mục trên các trường khóa gia tăng tới một mức nào đó mà khiến hiệu năng của việc thao tác với dữ liệu (đọc, thêm, sửa, xóa) suy giảm. Trong trường hợp đó, tốt hơn hết là sử dụng khóa chính ID mà chỉ mục của nó đủ nhỏ gọn và sinh ra những ràng buộc DBE cần thiết để duy trì tính duy nhất.
Báo cáo đề tài nghiên cứu khoa học và công nghệ cấp trường 2019
ThS. Hoàng Ngọc Cảnh – TT. Công nghệ thông tin 45
- Cho dữ liệu phân cấp không giới hạn liên kết với chính nó: Rất nhiều trường hợp ta gặp đó là dữ liệu với phân cấp cha con không giới hạn. Ví dụ như 1 lược đồ tiếp thị nhiều mức trong đó 1 nhân viên bán hàng có thể có nhiều nhân viên khác theo sau. Trong trường hợp này, sử dụng 1 khóa chính liên kết với chính nó và khóa ngoại sẽ giúp giải quyết vấn đề này.
- Tạo các hệ thống bảng lookup cố định: có rất nhiều thuộc tính ở các bảng khác nhau nhưng trùng nhau về dữ liệu, hơn nữa tập các dữ liệu này cũng được giới hạn về số lượng, khi đó ta nên tạo ra một bảng cố định lưu trữ tập dữ liệu nói trên để lookup cho tất cả các bảng cần đến nó. Ví dụ: các hóa đơn, các phiếu thu chi đều dùng đến một thuộc tính là nội dung thu chi, khi đó ta chỉ cần thiết kế một bảng lookup tên là “NoiDungThuChi” với khoảng 6 đến 7 nội dung thu chi cố định rồi liên kết đến các bảng “thuchi” và “nhapxuat”.
- Chú ý trong đặt tên các thực thể, đối tượng: Tên của bảng phải mô tả được thực thể mà nó đã nắm giữ và tên mỗi cột phải mô tả được phần thông tin mà nó đang thể hiện. Sau đây là một số hướng dẫn để đặt tên một cách đơn giản, ngắn gọn và dễ đọc: Không giới hạn kích cỡ tên bảng/cột. Một cách tên ý nghĩa sẽ dễ hiểu và dễ nhớ hơn tên viết tắt; Tên giống nhau có cùng một ý nghĩa. Tránh đặt tên cho các trường giống nhau với những kiểu dữ liệu hoặc ý nghĩa khác nhau; Nếu không cần thiết, loại bỏ sự dừ thừa. Ví dụ trong bảng Item, thay vì ItemName, PriceOfItem, hoặc tương tự thì Name và Price là đủ; Tránh những từ khóa mặc định của CSDL. Nếu một cột được gọi là Index, một từ khóa của SQL, thì cố gắng sử dụng một cái tên khác như IndexNumber; Nếu sử dụng khóa chính là cột số nguyên được sinh tự động, đặt tên cho nó là Id ở mọi bảng; Định nghĩa khóa ngoài khi nối bảng: thêm Id đằng trước tên bảng. Ví dụ IdItem; Nếu đặt tên cho ràng buộc thì sử dụng tiền tố mô tả ràng buộc (vd: PK hoặc FK), theo sau là tên của bảng hoặc bảng liên quan. Dĩ nhiên, việc sử dụng gạch dưới _ phần nào đó khiến mọi thứ trở nên dễ đọc hơn; Để đặt tên cho chỉ mục, sử dụng tiền tố IDX đằng trước tên bảng và tên cột hoặc cột của chỉ mục. Đồng thời sử dụng UNIQUE làm tiền tố hoặc hậu tố nếu chỉ mục là duy nhất và sử dụng gạch dưới nếu cần thiết. Có nhiều quy tắc đặt tên khác sẽ cụ thể hơn nhưng với những quy tắc cơ bản này, CSDL sẽ trở nên dễ đọc hơn. Điều quan trọng không phải là quy mô hay độ phức tạp của những quy tắc đặt tên mà là sự nhất quán khi áp dụng chúng.
- Không thể có nhiều giá trị trong 1 cột trong 1 bản ghi. Ví dụ nếu Fred có 3 xe ô tô nhưng bản ghi của Fred không nên có 1 cột Car với 3 giá trị trong đó. Càng có ít giá trị null trong các cột càng tốt, nên lựa chọn bảng để nhúng khóa trong đó khi nó có ít giá trị null. Các cột dữ liệu blob và image không nên định nghĩa trong các bảng thường xuyên truy vấn do vấn đề hiệu năng. Những dữ liệu này phải được đặt tại các bảng riêng và chúng sẽ được trỏ tới từ bảng được truy vấn.
Báo cáo đề tài nghiên cứu khoa học và công nghệ cấp trường 2019
ThS. Hoàng Ngọc Cảnh – TT. Công nghệ thông tin 46
- Khóa không nên dài quá. Nếu bạn đang thử quyết định giữa xác định 1 khóa với 2 cột (ví dụ Invoice Number và Date) và 1 khóa với 1 cột (ví dụ Invoice Number), cả 2 đều xác định duy nhất 1 dòng trong bảng, hãy lựa chọn khóa ngắn hơn trong 2 khóa. Khi định nghĩa 1 khóa, bạn cần chắc chắn rằng tập hợp thông tin này là cần và đủ để xác định 1 hàng, không nên có thêm hoặc ít hơn thông tin.
- Chỉ tạo 1 quan hệ mới giữa các thực thể nếu quan hệ này không thể được bắt nguồn từ quan hệ khác.
- Sử dụng trường id là số nguyên trong mọi bảng. Nếu hiện tại bảng chưa cần trường này thì sẽ có lúc cần trong tương lai (cho các bảng kết hợp, đánh index …). Lựa chọn các cột có kiểu giá trị số nguyên để đánh index. Đánh index trường có kiểu dữ liệu ký tự có thể sẽ gây ra các vấn đề về hiệu năng. Tạo Primary key (PK) trên mỗi bảng, thiết lập cho PK này là Clustered Index, trường hợp xấu nhất thì cũng phải có Non Clustered Index. Tạo index cho tất cả các cột được xác định là Foreign key, nếu biết chắc cột khóa ngoại này có giá trị là duy nhất thì cần tạo thuộc tính cho index của các FK này là Unique. Tạo UNIQUE INDEX cho các cột được dùng nhiều và thường xuyên trong điều kiện WHERE để truy cập database (email, username...).
- Phân vùng các bảng lớn, không sử dụng hoặc hiếm khi sử dụng vào các vùng lưu trữ vật lý khác nhau để truy vấn được tốt hơn. Máy chủ CSDL và máy chủ web nên để riêng biệt trên 2 server vật lý. Việc này sẽ đảm bảo bảo mật hơn (kẻ tấn công không thể tấn công trực tiếp dữ liệu). Hiệu năng bộ nhớ và CPU của server sẽ tốt hơn do giảm tải số lượng yêu cầu và các tiến trình xử lý.
- Với các hệ thống CSDL lớn, nhạy cảm nên sử dụng các dịch vụ bảo mật và khôi phục sau thảm họa như failover clustering, sao lưu tự động, nhân rộng …
4.2. Tối ưu trong viết lệnh truy vấn
Một số thủ thuật trong tối ưu truy vấn trên cơ sở dữ liệu như sau:
- Luôn tham chiếu đến các đối tượng bằng tên sở hữu đầy đủ trong four-part name, viết dbo.sysdatabases thay vì chỉ viết sysdatabases. (chỉ với SQL Server )
- Dùng các View hay Stored Procedure thay vì dùng những câu lệnh truy vấn dài. Cách này giúp chúng ta làm giảm giao dịch qua mạng, bởi vì máy khách chỉ cần gởi tên của View hay SP cho máy chủ( có thêm một số tham số) thay vì những dòng văn bản dài. Điều này cũng tạo điều kiện để quản lý phân quyền trong SQL Server, bởi vì bạn có thể hạn chế việc truy cập của các User đến những cột của một bảng mà họ không được truy vấn.
Báo cáo đề tài nghiên cứu khoa học và công nghệ cấp trường 2019
ThS. Hoàng Ngọc Cảnh – TT. Công nghệ thông tin 47
- Hạn chế việc viết và thực thi các câu truy vấn động cũng như viết mã truy vấn trong các chương trình. Thay vào đó hãy viết và thực thi trực tiếp trên môi trường của cơ sở dữ liệu thông qua các cửa sổ viết T-SQL, View, Stored, Functions.
- Hiểu được cơ chế và thứ tự thực hiện các lệnh Select, Join, Where, Group, Having, Distinct, Contrains, Top,… và đặc biệt hiểu về cách thức mà công cụ tối ưu của cơ sở dữ liệu chọn lựa thứ tự thực thi các mệnh đề điều kiện trong câu lệnh.
- Nên dùng Constraints thay cho Triggers, khi có thể. Constraints là hiệu quả hơn Triggers và giúp tăng tốc việc thực hiện. Vì vậy, bạn nên dùng Constraints thay cho Triggers ngay khi có thể.
- Dùng table variables thay vì dùng temporary tables. Table variables yêu cầu tài nguyên locking và logging ít hơn temporary tables. Vì vậy, Table variables nên được dùng ngay khi có thể.
- Nên dùng câu lệnh UNION ALL thay cho UNION, khi có thể. Câu lệnh UNION ALL là nhanh hơn UNION, bởi vì câu lệnh UNION ALL sẽ không tìm ra những dòng dữ liệu trùng nhau còn UNION sẽ tìm ra những dòng dữ liệu trùng nhau cho dù sự trùn đó có hay không.
- Nên tránh dùng mệnh đề DISTINCT, khi có thể. Bởi vì dùng mệnh đề DISTINCT kết quả thực thi sẽ chậm. Bạn chỉ nên dùng mệnh đề đó khi cần thiết.
- Tránh dùng Cursor trong SQL Server, khi có thể. Dùng Cursor trong SQL Server dẫn đến kết quả là làm giảm tốc độ hơn so với những câu lệnh Select. Cố gắng dùng các câu Select lồng nhau hay là dùng bảng tạm nếu muốn bạn muốn thao tác trên từng dòng dữ liệu.
- Nên tránh dùng mệnh đề HAVING, khi có thể. Mệnh đề HAVING dùng để giới hạn bớt kết quả trả về bởi mệnh đề GROUP BY. Khi dùng mệnh đề GROUP BY với mệnh đề HAVING, mệnh đề GROUP BY sẽ chia tất cả các dòng thành những tập hợp gồm nhiều tập hợp của các dòng và những giá trị của nó. Khi đó, mệnh đề HAVING sẽ hạn chế kết quả xuất ra không mong muốn của các tập hợp đó. Trong nhiều trường hợp, ta có thể viết câu lệnh SELECT mà chỉ có mệnh đề WHERE, GROUP BY không cần mệnh đề HAVING. Cách viết này sẽ cải thiện tốc độ câu truy vấn của bạn.
- Nếu chúng ta muốn lấy tổng số dòng trong bảng, chúng ta nên thay thế cách dùng câu lệnh thông thường là Select count(*). Bởi vì, câu lệnh Select count(*) yêu cầu thực hiện quét toàn bộ bảng để cho ra kết quả tổng số dòng. Điều này sẽ mất nhiều thời gian nếu bảng này chứa dữ liệu lớn. Có một cách khác để xác định tổng số dòng trong một bảng. Bạn có thể dùng bảng hệ thống là: sysindexes trong trường hợp này. Có cột tổng số dòng trong trong bảng. Cột này chứa tổng số dòng cho mỗi bảng trong
Báo cáo đề tài nghiên cứu khoa học và công nghệ cấp trường 2019
ThS. Hoàng Ngọc Cảnh – TT. Công nghệ thông tin 48
cơ sở dữ liệu.Vì vậy bạn có thể dùng câu lệnh sau thay vì dùng câu lệnh SELECT COUNT(*)
- Thêm câu lệnh SET NOCOUNT ON vào Stored Procedures để dừng thông báo về số dòng được thực thi bởi câu lệnh T-SQL. Điều này làm giảm giao dịch mạng, bởi vì máy khách sẽ không nhận được thông báo về số dòng bị tác động bởi câu lệnh T- SQL.
- Nên dùng mệnh đề WHERE để hạn chế bớt kết quả truy vấn. Điều này mang lại kết quả tốt cho các truy vấn. Bởi vì SQL chỉ trả về những dòng cụ thể cho máy khách, chứ không phải tất cả các dòng trong một bảng. Điều này làm giảm giao dịch qua mạng và tăng tốc câu lệnh truy vấn.
- Dùng những câu lệnh với từ khóa TOP hoặc câu lệnh SET ROWCOUNT nếu bạn muốn kết quả trả về chỉ là n dòng đầu tiên. Điều này có thể cải thiện tốc độ của