Tải bản đầy đủ (.pdf) (75 trang)

Nghiên cứu phương pháp xây dựng Storage Engine cho hệ quản trị cơ sở dữ liệu MySQL

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (1000.99 KB, 75 trang )


ĐẠI HỌC QUỐC GIA HÀ NỘI
TRƯỜNG ĐẠI HỌC CÔNG NGHỆ





NGUYỄN THỊ KHUÊ






NGHIÊN CỨU PHƯƠNG PHÁP XÂY DỰNG
STORAGE ENGINE CHO HỆ QUẢN TRỊ
CƠ SỞ DỮ LIỆU MYSQL





LUẬN VĂN THẠC SĨ CÔNG NGHỆ THÔNG TIN










Hà Nội – 2012


ĐẠI HỌC QUỐC GIA HÀ NỘI
TRƯỜNG ĐẠI HỌC CÔNG NGHỆ



NGUYỄN THỊ KHUÊ



NGHIÊN CỨU PHƯƠNG PHÁP XÂY DỰNG
STORAGE ENGINE CHO HỆ QUẢN TRỊ
CƠ SỞ DỮ LIỆU MYSQL



Ngành: Công nghệ thông tin
Chuyên ngành: Hệ thống thông tin
Mã số: 60 48 05



LUẬN VĂN THẠC SĨ CÔNG NGHỆ THÔNG TIN


NGƯỜI HƯỚNG DẪN KHOA HỌC: T.s Nguyễn Hải Châu






Hà Nội – 2012


2

MỤC LỤC
LỜI CAM ĐOAN 1
MỤC LỤC 2
DANH MỤC CÁC KÍ HIỆU VÀ CHỮ VIẾT TẮT 4
DANH MỤC CÁC BẢNG 4
DANH MỤC CÁC HÌNH VẼ 4
MỞ ĐẦU 5
CHƯƠNG 1. TỔNG QUAN VỀ MYSQL 7
1.1. Hệ quản trị cơ sở dữ liệu MySQL 7
1.2. Kiến trúc MySQL 9
1.3. Truy vấn dữ liệu trên MySQL 11
1.3.1. Giao diện SQL 11
1.3.2. Phân tách 11
1.3.3. Tối ưu truy vấn 12
1.3.4. Thực thi truy vấn 13
1.3.5. Bộ đệm truy vấn 13
1.3.6. Cache và Buffer 15
1.4. Các đặc trưng của MySQL 16
1.4.1. Quản lí kết nối và an ninh 16
1.4.2. Quản lí đồng thời 17

1.4.3. Giao tác 18
1.4.4. Điều khiển đồng thời đa phiên bản (MVCC) 21
1.4.5. Chỉ mục 22
CHƯƠNG 2. MYSQL PLUGGABLE STORAGE ENGINE 25
2.1. Storage engine là gì? 25
2.2. Kiến trúc pluggable storage engine 27
2.3. Một số storage engine điển hình 28
2.3.1. Một số storage engine có sẵn 28
2.3.1.1. MyISAM 28
2.3.1.2. InnoDB 31
2.3.1.3. Archive 36
2.3.1.4. Federated 36
2.3.1.5. NDB Cluster 39
2.3.1.6. Memory 39
2.3.1.7. Merge 40
2.3.1.8. Blackhole 42
2.3.1.9. CSV 42
2.3.2. Lưu trữ theo cột và storage engine 43
2.3.2.1. Kĩ thuật lưu trữ theo cột 43
2.3.2.2. InfoBright 45
2.3.3. NoSQL và storage engine 46
2.3.3.1. NoSQL là gì? 46
2.3.3.2. HandlerSocket 48
2.4. Sử dụng storage engine có sẵn 49
2.4.1. Lựa chọn storage engine phù hợp 49
2.4.2. Một số thao tác cơ bản 50



3


CHƯƠNG 3. XÂY DỰNG STORAGE ENGINE 53
3.1. Cơ sở hạ tầng của một storage engine 53
3.2. Mã nguồn của MySQL 54
3.3. Cấu trúc Handlerton 55
3.4. Lớp Handler 58
3.5. Quá trình tạo một storage engine mới 61
KẾT LUẬN 73
TÀI LIỆU THAM KHẢO 74


4


DANH MỤC CÁC KÍ HIỆU VÀ CHỮ VIẾT TẮT
Từ viết tắt Mô tả
CSDL Cơ sở dữ liệu
Hệ QTCSDL Hệ quản trị cơ sở dữ liệu
MVCC (Multiversion concurrence control) Điều khiển đồng thời đa phiên bản





DANH MỤC CÁC BẢNG
Tên bảng Trang
Bảng 2.1. Ma trận tương thích giữa các kiểu khóa trong InnoDB 32
Bảng 2.2. Bảng so sánh tính năng giữa CSDL quan hệ và NoSQL 35
Bảng 2.3. Bảng tổng kết một số đặc trưng của một số storage engine
trong MySQL

43





DANH MỤC CÁC HÌNH VẼ
Hình vẽ Trang
Hình 1.1. Kiến trúc MySQL Server 10
Hình 2.1. Kiến trúc bảng Federated 37
Hình 2.2. Kiến trúc InfoBright 45
Hình 2.3. Kiến trúc HandlerSocket 48
Hình 3.1. Lớp dẫn xuất của pluggable storage engine 59



5

MỞ ĐẦU
Hiệu suất thực thi là một tiêu chí quan trọng đánh giá sự thành công của một hệ cơ
sở dữ liệu. Đặc biệt trong thời đại bùng nổ thông tin hiện nay, khi mà khối lượng dữ
liệu cực lớn và tăng nhanh chóng, không ngừng kéo theo những đòi hỏi cao về tốc độ
cũng như tính hiệu quả của các hệ cơ sở dữ liệu. Tổ chức lưu trữ dữ liệu và triển khai
cơ chế truy cập dữ liệu (hay còn gọi là thiết kế vật lí cơ sở dữ liệu) là một trong những
giải pháp quan trọng, cơ bản được lựa chọn nhằm cải thiện đáng kể hiệu suất của hệ
thống. Tổ chức lưu trữ và truy cập dữ liệu hợp lí và hiệu quả có thể đem lại những hiệu
quả bất ngờ trong một số trường hợp.
Thực tế chỉ ra rằng, mặc dù hiện nay có rất nhiều cách thức lưu trữ và tổ chức truy
cập dữ liệu khác nhau, từ cách phân đoạn dữ liệu, tổ chức tệp trên các thiết bị, lưu đệm
các dữ liệu có tần suất truy cập thường xuyên, hay các cơ chế lập chỉ mục để truy cập

nhanh tới dữ liệu, … Tuy nhiên, mỗi cách thức có những ưu điểm và hạn chế riêng, có
thể tốt trong trường hợp này nhưng lại không hiệu quả trong trường hợp khác. Hay nói
một cách khác, không thể có cơ chế tốt nhất cho mọi trường hợp.
Hơn nữa, mỗi hệ quản trị cơ sở dữ liệu hiện nay chỉ có thể triển khai một hoặc một
vài cơ chế nhất định vì bản thân các cơ chế khác nhau có thể có những xung đột gây
ảnh hưởng lẫn nhau. Và tất nhiên hệ quả là, mỗi hệ quản trị cơ sở dữ liệu thường chỉ
đáp ứng tốt nhu cầu cho một hoặc một vài miền ứng dụng trong những trường hợp
nhất định.
Như vậy, có thể khẳng định rằng, không có cơ chế lưu trữ và truy cập tệp tốt cho
mọi trường hợp cũng như không thể triển khai mọi cơ chế truy cập tệp trong một hệ
quản trị cơ sở dữ liệu. Sẽ thật lí tưởng nếu có thể triển khai nhiều cơ chế tổ chức, truy
cập tệp như là các gói giải pháp để đáp ứng nhu cầu của từng ứng dụng cụ thể và dễ
dàng tra lắp cũng như gỡ bỏ ra khỏi hệ thống. Hệ quản trị cơ sở dữ liệu MySQL đã
thực sự làm được điều này thông qua việc triển khai các storage engine, nơi chứa một
tập các cơ chế lưu trữ, truy cập, hỗ trợ giao tác, các cơ chế khóa, cách ly, nhằm bổ
sung các kiểu lưu trữ mới, dễ dàng tra lắp vào máy chủ thông qua cơ chế pluggable
storage engine. Nó có thể là một storage engine đã được xây dựng sẵn hay bất kì một
storage engine tự phát triển mới. Vì vậy, MySQL có thể đáp ứng được nhiều nhu cầu
của nhiều ứng dụng trong nhiều hoàn cảnh khác nhau. Cơ chế pluggable storage
engine đã tạo nên tính linh hoạt, mềm dẻo có lẽ duy nhất có của MySQL, góp phần
không nhỏ vào sự thành công của MySQL với tư cách là một hệ quản trị cơ sở dữ liệu
mã nguồn mở phổ biến nhất hiện nay.
Đề tài “Nghiên cứu phương pháp xây dựng storage engine cho hệ quản trị cơ sở
dữ liệu MySQL” hướng tới tìm hiểu kiến trúc pluggable storage engine của MySQL.
Thông qua việc tìm hiểu một số storage engine điển hình và một số xu hướng lưu trữ
dữ liệu nổi bật hiện nay cùng một số storage engine tiêu biểu của xu hướng đó (như


6


lưu trữ dữ liệu theo cột với InfoBright, NoSQL với HandlerSocket), luận văn đưa ra
một cái nhìn tổng quan về MySQL storage engine cũng như một số gợi ý khi lựa chọn
storage engine phù hợp cho một ứng dụng. Đồng thời, luận văn cũng hướng tới việc
tìm hiểu những yếu tố cần cân nhắc khi xây dựng storage engine như lựa chọn cách tổ
chức lưu trữ dữ liệu, cách thức lưu đệm, hỗ trợ chỉ mục, hỗ trợ giao tác, các yêu cầu
đặc biệt,… và cuối cùng đi tới nghiên cứu một tiến trình xây dựng một storage engine
mới được cho là khả thi.
Nội dung chính của luận văn được chia thành 3 phần:
Chương 1: Tổng quan về hệ quản trị CSDL MySQL. Chương này giới thiệu
tổng quan về hệ quản trị cơ sở dữ liệu MySQL gồm: kiến trúc tổng quan của MySQL,
những đặc điểm cơ bản của MySQL và đặc biệt nhấn mạnh những điểm khác biệt của
MySQL so với các hệ QTCSDL khác như: sử dụng lớp pluggable storage engine cung
cấp tính linh hoạt cho MySQL bằng khả năng lựa chọn cơ chế lưu trữ và truy cập phù
hợp với từng ứng dụng; sử dụng các bộ đệm truy vấn và nhiều cơ chế lưu đệm khác
nhau để cải thiện tốc độ truy vấn; triển khai các cơ chế chỉ mục, quản lí giao tác và lập
chỉ mục tại các storage engine, …
Chương 2: MySQL Pluggable storage engine. Trong chương này đi sâu nghiên
cứu về một cơ chế đặc biệt có lẽ chỉ duy nhất có trong MySQL, pluggable storage
engine. MySQL đưa ra một khái niệm mới đặc biệt, storage engine, nhằm xây dựng
các cơ chế truy cập tệp phù hợp nhất với từng ứng dụng cụ thể. Phần này cũng tìm
hiểu một số storage engine có sẵn và một số xu hướng phát triển của các cơ chế tổ
chức, truy cập dữ liệu nổi bật hiện nay cùng một vài storage engine điển hình của các
xu hướng đó. Từ đó, đưa ra một số gợi ý khi lựa chọn storage engine sử dụng cho ứng
dụng của người dùng.
Chương 3. Xây dựng storage engine. Nghiên cứu một quy trình xây dựng
storage engine từ việc đưa ra các lựa chọn chức năng cần có của một storage engine,
tìm hiểu cấu trúc handlerton và lớp handler trong MySQL đến tiến trình các giai đoạn
thực hiện xây dựng một storage engine mới và cuối cùng là thử nghiệm chương trình
thực nghiệm cho tiến trình đó.



7

CHƯƠNG 1. TỔNG QUAN VỀ MYSQL
Sự phát triển mạnh mẽ của phong trào mã nguồn mở trong những năm gần đây đã
thực sự đem lại cho nền công nghiệp phần mềm những triển vọng mới. Ngay từ khi
được Richard Stallman khởi xướng (năm 1970) đến khi hệ điều hành Linux ra đời
(năm 1991, do Linux Torvalds người Phần Lan viết nhân) và cho đến ngày nay, phần
mềm mã nguồn mở dần khẳng định được vị thế của mình, với cộng đồng người phát
triển lên tới hàng triệu người trên khắp thế giới, cùng sự phổ biến của một số phần
mềm nguồn mở như Linux, Apache HTTP server, OpenSSL, MySQL, BIND,
Sendmail,… hay những câu chuyện thành công của các công ty kinh doanh mã nguồn
mở như MySQL AB, Red Hat, Slackware,… (điều mà những người chống phong trào
mã nguồn mở cho là “không tưởng”).
Trong phong trào đó, MySQL nổi lên như là một hệ quản trị cơ sở dữ liệu (hệ
QTCSDL) phổ biến nhất hiện nay với khoảng 8 triệu bản cài đặt trên khắp thế giới.
Vậy MySQL là gì? Cái gì khiến nó trở thành hệ QTCDL thành công đến như vậy?
1.1. Hệ quản trị cơ sở dữ liệu MySQL
MySQL là hệ QTCSDL thuộc sở hữu của MySQL AB, AB là từ viết tắt của từ
Thụy Điển “aktiebolag” nghĩa là công ty cổ phần hay công ty, được bắt đầu như một
liên minh vốn đầu tư với mục tiêu xây dựng một hệ cơ sở dữ liệu quan hệ nguồn mở
đáng tin cậy thay thế hệ cơ sở dữ liệu độc quyền thương mại. MySQL AB tạo ra doanh
thu bằng cách bán giấy phép thương mại, hỗ trợ và cung cấp các dịch vụ phát triển
chuyên nghiệp gồm tư vấn, đào tạo, chứng nhận sản phẩm.
MySQL là hệ QTCSDL quan hệ hỗ trợ đầy đủ các câu lệnh SQL. Nó cho phép
phát triển trên nhiều nền tảng phần cứng khác nhau. Hơn nữa, MySQL được phát triển
dựa trên ngôn ngữ C/C++, ngôn ngữ sử dụng để xây dựng gần như toàn bộ hệ điều
hành Linux cũng như Microsoft Windows và Macintosh. Nó được thiết kế dựa trên
kiến trúc client/server. MySQL được đánh giá là một hệ QTCSDL phát triển khá đầy
đủ và có độ tin cậy, tính ổn định, hiệu suất cao cũng như dễ sử dụng. Đặc biệt, MySQL

cung cấp một cơ chế tuyệt vời cho phép tổ chức lưu trữ dữ liệu theo nhiều cách khác
nhau để đạt hiệu quả cao nhất phù hợp với từng hoàn cảnh cụ thể gọi là pluggable
storage engine. Điều đó khiến cho MySQL được đánh giá là có tính linh hoạt rất cao.
Tại tầng thấp nhất của hệ thống, các máy chủ được xây dựng dựa trên mô hình đa
luồng. Về mặt chức năng, nhiều phần trong lõi của MySQL được xây dựng từ những
năm 1980. Đến năm 1995, ngôn ngữ truy vấn dữ liệu SQL được đưa vào hệ thống.
MySQL sử dụng trình biên dịch GNU C (GCC) có khả năng cung cấp tính mềm dẻo
tuyệt vời cho mọi môi trường đích.


8

Các công cụ máy khách của MySQL phần lớn được viết bằng ngôn ngữ C nên có
tính di động và tốc độ cao hơn. Các thư viện máy khách, các cơ chế truy cập có thể
được viết bằng bất kì ngôn ngữ lập trình nào như .Net, Java, ODBC,…
MySQL sử dụng chiến lược phát triển song song để đảm bảo vẫn duy trì các phiên
bản cũ trong khi phát triển các phiên bản mới. Việc này tạo nên sự khác biệt cơ bản so
với các phần mềm bản quyền thương mại, nơi mà ngay khi các nhà cung cấp đưa ra
phiên bản mới thì các phiên bản cũ bị dừng lại. Điều đó buộc các khách hàng phải thay
đổi môi trường cùng với các nỗ lực phát triển kèm theo, đặc biệt khi có những thay đổi
về mặt kiến trúc. Trong khi đó, MySQL cùng với chiến lược đa bản phát hành cho
phép người dùng duy trì các sản phẩm lâu dài hơn mà vẫn đảm bảo được hỗ trợ. Do
đó, khách hàng có nhiều thời gian chuẩn bị trước những bước thay đổi cần thiết đồng
thời có thể đảm bảo sử dụng tài nguyên hiệu quả nhất mà không phải vội vã thay đổi
kế hoạch dài hạn.
Sự phát triển của MySQL cũng như các phần mềm nguồn mở khác tuân theo tiến
trình gồm nhiều giai đoạn. Mỗi giai đoạn có thể có nhiều bản phân phối khác nhau.
Các giai đoạn phát triển như sau:
Giai đoạn 1: Giai đoạn phát triển (Development) – đây là giai đoạn mà các tập
tính năng hoặc sản phẩm mới được lập kế hoạch hoặc triển khai như một hướng phát

triển mới.
Giai đoạn 2: Alpha – là giai đoạn triển khai sàng lọc tính năng và chỉnh sửa
khiếm khuyết (sửa lỗi).
Giai đoạn 3: Beta – các tính năng được “đóng băng” (không thể thêm các tính
năng mới), bổ sung các kiểm thử chuyên sâu và triển khai dò tìm khiếm khuyết.
Giai đoạn 4: Gamma – Về cơ bản, các sản phẩm trong giai đoạn này là mã đã
được đóng băng và các vòng kiểm thử cuối cùng đã được tiến hành. Các sản phẩm
trong giai đoạn này thường là các ứng viên sẽ đưa ra phát hành.
Giai đoạn 5: Stable – Nếu không tìm thấy khiếm khuyết nghiêm trọng, mã được
công bố là ổn định và sẵn sàng để phân phối sản phẩm.
Khi sử dụng MySQL, tùy vào mục đích sử dụng của người dùng mà có thể lựa
chọn các bản phân phối phù hợp. Tuy nhiên, nên sử dụng phiên bản alpha mới nhất
cho những phát triển mới. Điều đó tạo ra cơ hội tốt hơn khi bản chỉnh sửa đã được
kiểm thử trước tại giai đoạn alpha.
MySQL là một hệ QTCSDL mã nguồn mở tuân thủ theo giấy phép nguồn mở
GPL (General Public License). MySQL AB sử dụng giấy phép nguồn mở GPL như là
điểm chính trong mô hình kinh doanh. MySQL AB thừa nhận cộng đồng mã nguồn
mở GNU cũng như các liên danh đầu tư với MySQL AB đều được kí kết dưới cùng
một triết lí và giấy phép.


9

Đặc biệt, MySQL sử dụng khái niệm cấp phép kép (dual – license). Có nghĩa là,
bên cạnh các sản phẩm tuân thủ đúng giấy phép nguồn mở GPL, MySQL cũng được
cấp phép như một sản phẩm thương mại. Một giấy phép thương mại cho phép MySQL
sở hữu mã nguồn, cũng như bản quyền về tên, logo, và các tài liệu liên quan. Đây là
điểm độc đáo khác hẳn với các công ty mã nguồn mở khác. MySQL AB giữ lại các tài
sản trí tuệ của phần mềm trong khi vẫn tận dụng sự hỗ trợ của cộng đồng những người
phát triển trên toàn cầu để mở rộng và phát triển phần mềm. Điều này đã khiến cho

MySQL nhanh chóng trở thành một hệ QTCSDL mã nguồn mở ổn định, có tính linh
hoạt và phổ biến nhất hiện nay.
Vấn đề đặt ra là, khi MySQL vừa được cấp phép như phần mềm nguồn mở vừa
được coi là phần mềm thương mại thì liệu có thực sự được phép chỉnh sửa hay không?
Câu trả lời là có. Bất kì người phát triển nào đều có thể chỉnh sửa MySQL, tất nhiên
phải tuân thủ giấy phép nguồn mở GPL. Đồng thời cũng có thể chỉnh sửa dưới giấy
phép thương mại trong trường hợp muốn sử dụng bản chỉnh sửa cho những phát triển
riêng hoặc gói hay nhúng MySQL vào trong sản phẩm thương mại đã có.
1.2. Kiến trúc MySQL
So với rất nhiều hệ CSDL khác, MySQL có rất nhiều khác biệt. Mặc dù MySQL
không hoàn hảo nhưng nó lại được đánh giá là một hệ QTCSDL linh hoạt có khả năng
làm việc tốt trong nhiều môi trường khác nhau đáp ứng nhiều mục đích đa dạng, đặc
biệt là trong các ứng dụng web. Hiện nay, MySQL có khả năng triển khai trong các
ứng dụng nhúng, kho dữ liệu, lập chỉ mục nội dung và các phần mềm phân phối, các
hệ thống đòi hỏi tính sẵn sàng cao, các xử lí giao tác trực tuyến (OLTP), … MySQL
vô cùng linh hoạt theo nhiều cách khác nhau. Nó có thể được cấu hình để chạy tốt trên
nhiều nền tảng phần cứng và hỗ trợ cho nhiều kiểu dữ liệu khác nhau thông qua một
cơ chế độc đáo chỉ có duy nhất trên MySQL, pluggable storage engine. Các storage
engine được thiết kế độc lập với xử lí truy vấn và các nhiệm vụ khác trong máy chủ
như một trình runtime plugin. Tùy vào ứng dụng cụ thể, có thể lựa chọn cách thức lưu
trữ dữ liệu, cách thể hiện và các đặc trưng tối ưu nhất thông qua việc lựa chọn các
storage engine đã có phù hợp, hay tự xây dựng storage engine riêng.
Kiến trúc hệ thống MySQL được mô tả như là một hệ thống phân lớp các hệ thống
con. Trong khi mã nguồn chưa được biên dịch thành các phần hoặc mô-đun riêng, mã
nguồn của các hệ thống con được tổ chức dưới dạng cây phân cấp. Hệ thống được phát
triển dựa trên các thư viện cơ sở cung cấp các chức năng mức thấp như điều khiển
luồng, tổ chức lưu trữ trong bộ nhớ, các thao tác mạng, đăng nhập, và thậm chí cả điều
khiển truy cập và các thao tác quản lí. Các thư viện này được kết hợp với nhau tạo
thành các hệ thống con và các hệ thống con có thể được xây dựng dựa trên các hệ
thống con khác. Các hệ thống giao tiếp thông qua một giao diện API chuẩn. Giao diện

API này cho phép hệ thống MySQL vừa được sử dụng như một máy chủ độc lập, vừa


10

như một hệ CSDL nhúng trong một ứng dụng lớn hơn. Kiến trúc của MySQL được mô
tả chi tiết như hình 1.1 sau:

Hình 1.1. Kiến trúc của MySQL server, trong [4, pp.1185]
Lớp trên cùng là các lớp kết nối cơ sở dữ liệu (Connector): cung cấp phương thức
truy cập cho các ứng dụng máy khách. Các ứng dụng này có thể được viết bằng bất kì
ngôn ngữ nào như C, .Net, PHP, ODBC, ….
Các công cụ phụ trợ được nhóm trong nhóm các tiện ích và dịch vụ quản lí gồm
sao lưu và khôi phục dữ liệu, an ninh, nhân bản, phân cụm, quản trị, cấu hình, …
Lớp nằm ngay dưới lớp kết nối là lớp connection pool. Đây là lớp quản lí tất cả
các truy cập của người dùng như xác thực người dùng, xử lí luồng, bộ nhớ, bộ đệm
tiến trình cần thiết cho một kết nối của máy khách.
Lớp kế tiếp là lớp quan trọng nhất của một hệ thống CSDL, nơi xử lí các truy vấn
người dùng. Tại lớp này, các truy vấn được đưa vào thông qua giao diện SQL, sau đó
được phân tách, tối ưu, thực thi và lưu đệm.
Sự độc đáo của MySQL được thể hiện trong lớp plugable storage engine. Lớp này
tạo nên sự linh hoạt cho hệ thống thông qua việc xây dựng các cách thức quản lí dữ
liệu hoặc lưu trữ tệp hoặc các cơ chế truy cập đa dạng khác nhau. Tính mềm dẻo này là
duy nhất có ở MySQL. Storage engine cung cấp khả năng điều chỉnh CSDL bằng cách
cung cấp một vài cơ chế lưu trữ dữ liệu. Máy chủ kết nối với các storage engine thông
qua một giao diện storage engine chuẩn. Giao diện này che giấu sự khác nhau giữa các
storage engine và khiến chúng trong suốt tại tầng truy vấn. Giao diện API chứa các
chức năng mức thấp thực hiện các quá trình như là bắt đầu giao tác hoặc thêm dữ liệu



11

vào một hàng với khóa chính đã biết, … Các storage engine không phân tách SQL
hoặc kết nối với các storage engine khác; chúng chỉ trả lời yêu cầu từ một máy chủ.
Tầng thấp nhất của hệ thống là lớp truy cập tệp. Tầng này chứa các cơ chế lưu trữ,
đọc và ghi dữ liệu, hệ thống đọc và ghi các thông tin biên bản và sự kiện. Đây cũng là
lớp gần nhất với hệ điều hành cùng với các điều khiển luồng, tiến trình và bộ nhớ.
1.3. Truy vấn dữ liệu trên MySQL
MySQL là một hệ QTCSDL quan hệ. Các yêu cầu người dùng được đưa vào
thông qua giao diện SQL, sau đó được phân tách, tối ưu, thực thi và cuối cùng, kết quả
được gửi lại cho người dùng thông qua giao diện SQL.
1.3.1. Giao diện SQL
Giao diện SQL cung cấp các cơ chế để nhận các câu lệnh và chuyển kết quả tới
người dùng. Giao diện SQL của MySQL được xây dựng trên chuẩn ANSI (American
National Standards Institute) và chấp nhận mọi câu lệnh SQL cơ bản như mọi máy chủ
CSDL theo chuẩn ANSI khác. Mặc dù rất nhiều câu lệnh trong MySQL có các lựa
chọn không theo chuẩn ANSI nhưng những người phát triển vẫn tìm thấy điểm tương
đồng với chuẩn này.
Khi nhận được một yêu cầu kết nối tới máy chủ CSDL từ đường truyền mạng, một
luồng (thread) được tạo ra cho mỗi kết nối. Tiến trình xử lí luồng là phần quan trọng
nhất trong máy chủ MySQL. MySQL được xây dựng như một ứng dụng đa luồng thực
sự nơi mà mỗi luồng được thực thi độc lập so với các luồng khác. Các câu lệnh SQL
được lưu trữ theo một cấu trúc phân lớp và các kết quả được gửi tới người dùng bằng
cách ghi các kết quả đó ra các phương thức truyền thông mạng.
1.3.2. Phân tách
Khi một máy khách gửi tới một truy vấn, một luồng mới được tạo ra. Câu lệnh
SQL được chuyển tới bộ phân tách để xác nhận cú pháp (hoặc từ chối nếu có lỗi). Bộ
phân tách của MySQL sử dụng kịch bản Lex-YACC được biên dịch bằng Bison. Bộ
phân tách sẽ xây dựng một cấu trúc truy vấn để thể hiện câu truy vấn viết bằng ngôn
ngữ SQL trên bộ nhớ trong như là một cấu trúc cây (hay còn gọi là cây cú pháp trừu

tượng). Sau đó sử dụng cấu trúc đó để thực thi truy vấn.
Bộ phân tách sẽ đọc câu lệnh SQL, sau đó tách câu lệnh thành các phần và gán các
tham số, các lựa chọn, các đoạn lệnh cho một cấu trúc các biến và danh sách. Cấu trúc
này sẽ được sử dụng cho mọi bước tiếp theo của tiến trình truy vấn. Cấu trúc Lex chứa
một danh sách các bảng được sử dụng, các tên trường tham chiếu đến, các điều kiện,
các biểu thức và tất cả các phần của câu truy vấn đó trên những không gian lưu trữ
phân biệt.


12

Bộ phân tách đọc các câu lệnh SQL và so sánh các biểu thức (gồm các token và
các kí hiệu) với các luật định nghĩa trong mã nguồn. Các luật này được xây dựng trong
mã nguồn sử dụng Lex và YACC và sau đó được biên dịch bằng Bison để phù hợp với
bộ phân tích từ vựng.
Ngay khi bộ phân tách xác thực một biểu thức và tách câu truy vấn thành các
phần, nó gán kiểu câu lệnh thích hợp cho cấu trúc luồng đó và trả điều khiển cho bộ xử
lí câu lệnh. Bộ xử lí câu lệnh giống như bộ chuyển đổi câu lệnh. Bộ phân tách truy vấn
chỉ kiểm tra tính đúng đắn của các câu lệnh SQL chứ không xác minh sự tồn tại của
các bảng hoặc các thuộc tính được tham chiếu cũng như không kiểm tra các lỗi ngữ
nghĩa như là sử dụng một hàm hợp mà không sử dụng mệnh đề GROUP BY. Thay vào
đó, việc xác thực được đưa tới quá trình tối ưu hóa. Do đó, cấu trúc truy vấn từ bộ
phân tách được đưa tới bộ xử lí truy vấn và điều khiển được chuyển tới bộ tối ưu truy
vấn.
1.3.3. Tối ưu truy vấn
MySQL sử dụng chiến lược SELECT – PROJECT – JOIN để cố gắng xây dựng
lại truy vấn. Đầu tiên, sử dụng câu lệnh SELECT để hạn chế số lượng các tuples, sau
đó thực hiện phép chiếu để để giảm số lượng các thuộc tính (trường) trên các tuples
kết quả và cuối cùng thực hiện lệnh hợp theo điều kiện.
Bước đầu tiên của quá trình tối ưu hóa là kiểm tra sự tồn tại của bảng và quyền

truy cập của người dùng. Nếu có lỗi thì một thông báo lỗi được đưa ra và điều khiển
được trả về cho trình quản lí luồng. Ngay khi các bảng được xác thực, chúng sẽ được
mở và các khóa thích hợp sẽ được sử dụng để điều khiển đồng thời.
Ngay khi các công việc cài đặt và bảo trì được hoàn thành, trình tối ưu sử dụng
cấu trúc truy vấn bên trong được phân tích bởi Lex và đánh giá điều kiện WHERE của
truy vấn đó. Các kết quả trả về như là các bảng tạm thời để chuẩn bị cho bước tiếp
theo. Nếu có xuất hiện phép toán UNION, trình tối ưu thực thi các đoạn SELECT của
tất cả các câu lệnh trong vòng lặp trước khi tiếp tục.
Bước tiếp theo của quá trình tối ưu hóa là thực thi phép chiếu. Chúng được thực
hiện theo cách thức tương tự như các đoạn giới hạn, lặp lại lưu trữ các kết quả tức thời
như các bảng tạm thời và chỉ lưu lại các thuộc tính được chỉ định trong các cột được
chỉ định trong câu lệnh SELECT. Sau đó, cấu trúc được phân tích cho bất kì điều kiện
JOIN nào được xây dựng sử dụng lớp join và gọi tới phương thức join::optimize(). Tại
bước này, truy vấn được tối ưu hóa thông qua việc đánh giá biểu thức và loại bỏ các
điều kiện mà kết quả trong các nhánh chết hoặc các điều kiện luôn đúng hoặc luôn sai.
Trình tối ưu cố gắng loại bỏ các điều kiện tri thức tồi (known – bad) trong câu truy vấn
trước khi thực thi lệnh join bởi vì lệnh join tốn nhiều chi phí cũng như thời gian nhất
trong tất cả các phép toán quan hệ. Cũng lưu ý rằng, bước tối ưu phép toán join được
thực hiện cho mọi câu lệnh có mệnh đề WHERE hoặc HAVING bất kể nó có điều


13

kiện join hay không. Ngay khi tối ưu câu lệnh join được hoàn thành, trình tối ưu sử
dụng một danh sách các câu lệnh điều kiện để định tuyến truy vấn tới một phương thức
thư viện thích hợp để thực thi.
1.3.4. Thực thi truy vấn
Gồm một tập các phương thức thư viện được thiết kế để triển khai các truy vấn cụ
thể. Ví dụ, phương thức mysql_insert() được thiết kế để chèn dữ liệu, phương thức
mysql_select() được thiết kế để tìm và trả ra dữ liệu thỏa mãn mệnh đề WHERE. Thư

viện các phương thức này được lưu trữ trong rất nhiều tệp mã nguồn dưới cùng một
tên tệp (ví dụ như sql_insert.cc hoặc sql_select.cc). Tất cả các phương thức đó đều có
một tham số như một đối tượng luồng cho phép phương thức đó truy cập vào cấu trúc
truy vấn bên trong và dễ dàng thực thi. Kết quả thực thi của mỗi phương thức được trả
về sử dụng thư viện đường truyền thông mạng.
1.3.5. Bộ đệm truy vấn
Rất nhiều hệ QTCSDL lưu lại các kế hoạch thực thi truy vấn (plan), do đó máy
chủ có thể bỏ qua các bước phân tách và tối ưu hóa cho các truy vấn lặp lại. MySQL
không những làm được điều đó mà còn cho phép lưu đệm tập các kết quả truy vấn cho
các câu lệnh SELECT. Đây có thể coi là kĩ thuật duy nhất có trong MySQL.
Bộ nhớ đệm truy vấn giữ lại chính xác các bit của kết quả truy vấn trả về cho
người dùng. Khi có một truy vấn đã được thực hiện trước đó rồi (xảy ra cache hit),
thay vì phân tách, tối ưu và thực thi câu truy vấn, máy chủ chỉ đơn giản trả ra các kết
quả đã được lưu trữ trước đó ngay lập tức. Điều này làm tăng hiệu suất xử lí truy vấn.
Bộ nhớ đệm truy vấn sẽ lưu vết tới các bảng mà câu truy vấn đó dùng, và nếu một
trong các bảng đó thay đổi, nó sẽ làm mất hiệu lực truy cập vào bộ đệm cache. Chính
sách làm mất hiệu lực thô này dường như không hiệu quả khi những thay đổi trên bảng
có thể không ảnh hưởng tới các kết quả lưu trữ trong bộ đệm nhưng đó là hướng tiếp
cận đơn giản với chi phí thấp, điều này rất quan trọng với các hệ thống thường xuyên
bận.
Bộ đệm truy vấn được thiết kế hoàn toàn trong suốt đối với các ứng dụng. Các ứng
dụng không cần biết dữ liệu được MySQL trả ra là từ trong bộ đệm hay do quá trình
thực hiện truy vấn trên thực tế. Các kết quả này là như nhau hay nói cách khác, bộ đệm
truy vấn thường không làm thay đổi ngữ nghĩa.
MySQL làm thế nào để kiểm tra một câu lệnh đã được thực thi trước đó hay chưa?
Cách thức mà MySQL sử dụng ở đây vô cùng đơn giản và khá nhanh: bộ đệm là một
bảng tìm kiếm. Khóa tìm kiếm là một giá trị băm của câu truy vấn đó, CSDL đang sử
dụng, phiên bản giao thức của máy khách và một giá trị hữu dụng có thể làm ảnh
hưởng tới các giá trị byte thực tế trong kết quả truy vấn.



14

MySQL không phân tích cú pháp, “bình thường hóa” hoặc tham số hóa một câu
lệnh khi kiểm tra câu lệnh đã được thực thi hay chưa. Nó sử dụng chính xác câu lệnh
và các bit dữ liệu khác mà người dùng gửi tới. Bất kì sự khác biệt nào như là trong các
kí tự, khoảng trống hoặc chú thích đều có thể khiến câu truy vấn đó không tương thích
với câu truy vấn đã được lưu đệm trước đó. Vì thế nên cẩn thận khi viết câu truy vấn.
Sử dụng các kiểu và định dạng nhất quán là một thói quen tốt nhưng trong trường hợp
này nó còn có thể giúp hệ thống nhanh hơn.
Kết quả truy vấn sẽ không được lưu đệm nếu như câu truy vấn sinh ra nó không
xác định. Vì thế bất kì câu lệnh nào chứa các hàm không xác định như NOW(),
CURRENT_DATE(), CURRENT_USER() hoặc CONNECTION_ID() đều sẽ không
được lưu đệm. Trong thực tế, bộ đệm truy vấn không làm việc với truy vấn yêu cầu
các hàm do người dùng định nghĩa, các hàm lưu trữ, các biến người dùng, các bảng
tạm thời, các bảng trong CSDL mysql, hoặc bất kì bảng nào chứa một độc quyền mức
dòng. Vậy MySQL có thực sự không kiểm tra bộ đệm nếu truy vấn chứa một hàm
không xác định không? Thực ra không đúng như vậy, MySQL không thể biết một câu
truy vấn có chứa một hàm không xác định trừ khi nó phân tách câu truy vấn đó, và
việc tìm kiếm bộ đệm diễn ra trước khi thực hiện phân tách câu truy vấn. Máy chủ lúc
này chỉ kiểm tra xem câu truy vấn đó có bắt đầu bằng các kí tự SEL hay không.
Bộ đệm truy vấn của MySQL có thể cải thiện hiệu suất nhưng nó cũng có một vài
vấn đề cần lưu ý khi sử dụng. Khi sử dụng bộ đệm truy vấn sẽ làm tăng thêm chi phí
khi đọc và ghi dữ liệu:
 Các truy vấn đọc dữ liệu phải kiểm tra bộ đệm trước khi bắt đầu.
 Nếu truy vấn đó được lưu đệm và chưa nằm trong bộ đệm, cần phải mất phí để
lưu trữ kết quả sau khi sinh nó.
 Việc ghi dữ liệu cho các câu lệnh cũng mất chi phí. Khi ghi dữ liệu phải làm
mất hiệu lực truy cập vào bảng đang thay đổi của tất cả các truy vấn khác.
Tuy nhiên, chi phí này không lớn lắm do đó bộ đệm truy vấn vẫn đạt được hiệu

quả khả thi. Nhưng vẫn còn một số vấn đề khác làm tăng thêm chi phí. Đối với những
người sử dụng InnoDB, các giao tác có thể hạn chế tính hữu ích của bộ đệm truy vấn.
Khi một câu lệnh bên trong một giao tác chỉnh sửa một bảng, máy chủ sẽ làm mất hiệu
lực của bất kì câu truy vấn đã được lưu đệm tham chiếu tới bảng đó, ngay cả khi tính
đa phiên bản của InnoDB có thể che giấu những thay đổi của giao tác với các câu lệnh
khác, bảng đó cũng không thể lưu đệm toàn cục cho đến khi giao tác được commit. Do
đó, không có câu truy vấn nào trên bảng (cả bên ngoài và bên trong giao tác) có thể
được lưu trữ cho đến khi giao tác được commit. Như vậy, một giao tác có thời gian
thực thi lâu sẽ làm tăng số lượng các bộ đệm truy vấn bị nhỡ.
Việc làm mất hiệu lực cũng trở thành một vấn đề khi bộ đệm truy vấn lớn. Nếu có
quá nhiều truy vấn trên bộ đệm, việc làm mất hiệu lực có thể mất nhiều thời gian và


15

khiến cho toàn bộ hệ thống ngưng lại trong khi nó vẫn đang làm việc. Điều đó xảy ra
do có một khóa toàn cục trên bộ đệm truy vấn sẽ chặn tất cả các truy vấn cần tham
chiếu đến nó. Quá trình truy cập diễn ra cả khi kiểm tra truy vấn đã được thực hiện
trước đó hay chưa và khi kiểm tra có bất kì truy vấn không hợp lệ.
1.3.6. Cache và Buffer
Cache và Buffer đảm bảo dữ liệu có tần suất sử dụng thường xuyên nhất phải sẵn
sàng theo cách thức hiệu quả nhất có thể. Nói cách khác, dữ liệu phải thường trú và
sẵn sàng được đọc tại mọi thời điểm. Cache làm giảm thời gian phản hồi cho các yêu
cầu dữ liệu bởi vì dữ liệu nằm ngay trong bộ nhớ trong mà không cần thiết phải truy
tìm dữ liệu trên đĩa. Hệ thống Cache được tạo ra để đóng gói tất cả các thao tác lưu
đệm trong tập các hàm chuẩn. Bộ nhớ đệm thường được triển khai trong các phần khác
nhau của mã nguồn để phù hợp với kiểu dữ liệu được lưu đệm. Các loại bộ đệm bao
gồm:
Bộ đệm bảng: tối thiểu chi phí mở, đọc và đóng bảng (tệp .frm trên đĩa). Bộ đệm
bảng được thiết kế để lưu trữ các metadata của bảng trong bộ nhớ trong. Điều đó khiến

cho một luồng (thread) đọc lược đồ của một bảng nhanh hơn mà không cần phải mở
lại tệp đó mỗi khi truy cập đến. Mỗi một luồng có danh sách các cấu trúc bộ đệm bảng
của riêng nó. Nó cho phép các luồng duy trì khung nhìn riêng của các bảng để nếu một
luồng đang thay đổi một lược đồ bảng (nhưng chưa commit) thì các luồng khác có thể
sử dụng bảng đó với lược đồ ban đầu. Cấu trúc này được lưu như một danh sách kết
nối trong bộ nhớ trong và tương thích với mỗi luồng.
Bộ đệm bản ghi: nâng cao khả năng đọc dữ liệu tuần tự từ các storage engine. Bộ
đệm bản ghi thường chỉ được sử dụng trong khi duyệt bảng. Nó hoạt động giống như
một bộ đệm đọc trước (read-ahead buffer) bằng cách tìm kiếm trên một khối (block)
dữ liệu, nên làm giảm việc truy cập đĩa trong quá trình duyệt. Như vậy hiệu suất sẽ
được cải thiện. Bộ đệm bản ghi cũng được sử dụng trong quá trình ghi dữ liệu một
cách tuần tự bằng cách trước tiên ghi dữ liệu mới (hoặc sửa đổi) vào bộ nhớ đệm, sau
đó ghi dữ liệu từ bộ đệm vào đĩa khi đầy. Bằng cách đó, hiệu suất ghi sẽ được cải
thiện.
Bộ đệm khóa: là bộ đệm được sử dụng cho các dữ liệu chỉ mục thường xuyên. Bộ
đệm khóa được truy cập trong mọi thao tác đọc chỉ mục. Nếu một chỉ mục được tìm
thấy trong bộ đệm thì nó sẽ được đọc từ đó; ngược lại, một khối chỉ mục mới phải
được đọc từ đĩa và đặt vào bộ đệm. Kích thước bộ đệm có giới hạn cho nên không phải
mọi khối của tệp chỉ mục được lưu trữ trong bộ nhớ trong. Làm thế nào để hệ thống
biết được khối nào vừa mới được sử dụng? Giải pháp đưa ra là sử dụng một hệ giám
sát để kiểm soát tần suất sử dụng của các khối chỉ mục bằng cách lưu lại giá trị warm.
Warm nhận các giá trị: lạnh (BLOCK_COLD), ấm (BLOCK_WARM), và nóng
(BLOCK_HOT). Khi các khối nguội và các khối mới trở nên ấm, các khối lạnh bị


16

thanh lọc, các khối ấm được bổ sung vào. Nó sử dụng chiến lược thay thế trang, bộ
đệm khóa sẽ lưu vết các khối chỉ mục bị thay đổi (gọi là bị vấy bẩn – dirty). Khi một
khối bị thay đổi (dirty) được thanh lọc, dữ liệu của nó được ghi trở lại tệp chỉ mục

trước khi bị thay thế. Ngược lại, khi một khối sạch (clean) được thanh lọc, nó đơn giản
chỉ bị xóa ra khỏi bộ nhớ trong.
Bộ đệm quyền truy cập: được sử dụng để lưu trữ các dữ liệu cấp quyền trên một
tài khoản người dùng. Dữ liệu này được lưu trữ theo cùng một cách với danh sách điều
khiển truy cập, nơi lập danh sách toàn bộ quyền của một người dùng đối với một đối
tượng trong hệ thống. Bộ đệm quyền sử dụng bảng băm FILO (vào trước, ra sau). Dữ
liệu của bộ đệm được thu thập khi đọc các bảng phân quyền trong quá trình khởi tạo
và xác thực người dùng. Việc lưu trữ các quyền đó trong bộ nhớ trong có thể tiết kiệm
nhiều thời gian so với việc đọc dữ liệu từ bảng.
Bộ đệm tên máy chủ (hostname): là bộ đệm chuyên dụng sử dụng cấu trúc ngăn
xếp. Nó chứa tên máy chủ của tất cả các kết nối tới máy chủ. Đây là dữ liệu được yêu
cầu thường xuyên.
Ngoài các cơ chế lưu đệm trên, MySQL cũng sử dụng thêm một số cơ chế khác để
làm tăng hiệu suất sử dụng của toàn bộ hệ thống.
Như vậy, giống như mọi hệ QTCSDL quan hệ khác, quá trình truy vấn dữ liệu của
MySQL cũng tuân thủ theo đúng tiến trình truy vấn gồm các bước cơ bản như phân
tách, tối ưu hóa, thực thi truy vấn. MySQL hỗ trợ đầy đủ các câu lệnh SQL theo chuẩn
ANSI, quá trình phân tách sử dụng kịch bản Lex – YACC, tối ưu truy vấn sử dụng
chiến lược SELECT – PROJECT – JOIN, truy vấn được thực thi thông qua các
phương thức thư viện chuẩn. Hơn nữa, MySQL còn sử dụng rất nhiều cơ chế lưu đệm
hiệu quả để làm tăng hiệu suất truy vấn dữ liệu, đặc biệt là cơ chế lưu đệm các kết quả
truy vấn. Đây chính là điểm độc đáo của MySQL.
1.4. Các đặc trưng của MySQL
1.4.1. Quản lí kết nối và an ninh
Khi có một yêu cầu kết nối từ một máy khách tới một máy chủ, kết nối đó phải
giành được một luồng (thread) riêng bên trong tiến trình của máy chủ. Các truy vấn
trong kết nối thực thi trong một luồng đơn lẻ, nằm trên một lõi hay một CPU. Máy chủ
lưu đệm các luồng, do đó không cần được tạo mới và hủy bỏ cho mỗi lần kết nối.
Khi các máy khách (ứng dụng) kết nối tới máy chủ MySQL, máy chủ cần xác thực
máy khách (hay ứng dụng) đó. Quá trình xác thực dựa trên tên người dùng, địa chỉ

host ban đầu, và mật khẩu. Giấy chứng nhận X. 509 cũng có thể được sử dụng thông
qua một kết nối Secure Sockets Layer (SSL). Khi một máy khách được kết nối, máy
chủ xác thực liệu máy khách đó có quyền cho mỗi truy vấn mà nó đệ trình hay không.


17

1.4.2. Quản lí đồng thời
Khi có nhiều truy vấn đồng thời yêu cầu dữ liệu tại cùng một thời điểm, MySQL
sẽ xử lí như thế nào? MySQL thực hiện quản lí đồng thời tại 2 mức: mức máy chủ và
mức storage engine. Ở đây chỉ xét quản lí đồng thời cho các thao tác đọc và ghi dữ
liệu.
Khi nhiều máy khách cùng đọc cùng một dữ liệu đồng thời, không có vấn đề gì
xảy ra, do không có sự thay đổi dữ liệu. Nhưng chuyện gì sẽ xảy ra nếu một máy
khách cố gắng đọc dữ liệu trong khi một máy khách khác đang thay đổi nó. Cũng
giống như các hệ QTCSDL khác, MySQL sử dụng các cơ chế khóa để ngăn không cho
máy khách đọc dữ liệu khi nó đang được thay đổi.
MySQL sử dụng 2 loại khóa:
- Khóa chia sẻ (shared lock - S) hay khóa đọc (read lock): các khóa đọc trên một
tài nguyên được chia sẻ, nghĩa là nhiều máy khách có thể đọc một tài nguyên tại một
thời điểm mà không ảnh hưởng đến nhau.
- Khóa độc quyền (exclusive lock - X) hay khóa ghi (write lock): khi có một máy
khách thực hiện thao tác ghi dữ liệu thì mọi thao tác đọc tới dữ liệu đó bị chặn.
Các khóa độc quyền (X) có độ ưu tiên cao hơn các khóa chia sẻ (S). Vì thế, một
yêu cầu khóa ghi sẽ được đẩy lên trước trong hàng đợi khóa ngay cả khi quá trình đọc
đã sẵn sàng trên hàng đợi.
Phạm vi khóa (Lock Granularity): Nhằm cải thiện hiệu suất sử dụng của một
tài nguyên, nên lựa chọn những thứ sẽ bị khóa. Thay vì khóa toàn bộ tài nguyên, hiệu
quả sẽ tốt hơn nếu chỉ khóa trên phần dữ liệu cần thay đổi. Tốt hơn nữa, chỉ khóa
chính xác những dữ liệu định thay đổi. Giảm thiểu lượng dữ liệu bị khóa tại một thời

điểm làm cho hiệu quả sử dụng đồng thời các tài nguyên tốt hơn, miễn là chúng không
xung đột với nhau.
Vấn đề là các khóa cũng sử dụng tài nguyên. Tất cả các bước trong tiến trình khóa
gồm lấy một khóa, kiểm tra khóa đó có rỗi hay không, giải phóng một khóa, … đều có
chi phí nhất định. Nếu một hệ thống dành quá nhiều thời gian quản lí khóa thay vì lưu
trữ và truy tìm dữ liệu, hiệu suất có thể bị ảnh hưởng xấu.
Một chiến lược khóa là sự thỏa hiệp giữa chi phí khóa và tính an toàn của dữ liệu,
và sự thỏa hiệp đó ảnh hưởng tới hiệu suất. Hầu hết các máy chủ CSDL thương mại
không có nhiều lựa chọn khóa nhưng MySQL lại cung cấp nhiều lựa chọn khóa thông
qua các storage engine. Các storage engine có thể triển khai các chiến lược khóa và
phạm vi khóa của riêng nó. Việc quản lí khóa là một quyết định rất quan trọng khi
thiết kế storage engine. Sử dụng các khóa ở các mức nhất định nào đó có thể đạt được
hiệu quả cao hơn trong trường hợp này nhưng lại kém hơn trong trường hợp khác. Bởi
vì MySQL cung cấp nhiều storage engine với rất nhiều chiến lược khóa khác nhau nên


18

nó không yêu cầu một giải pháp chung. Tuy nhiên, MySQL thường sử dụng hai chiến
lược khóa quan trọng sau:
Các khóa mức bảng (Table lock): là chiến lược khóa cơ bản nhất và có chi phí
thấp nhất trong MySQL. Một khóa bảng sẽ khóa toàn bộ bảng. Khi một máy khách
muốn ghi dữ liệu vào một bảng (insert, delete, updade, …), nó yêu cầu một khóa ghi
(X). Mọi thao tác đọc/ghi dữ liệu khác lên bảng đó đều bị chặn. Khi không đang thực
hiện thao tác ghi trên bảng, các khóa đọc (S) được cấp cho người đọc, miễn là chúng
không xung đột với các khóa đọc khác.
Các biến thể của khóa mức bảng có thể đạt được hiệu suất tốt hơn trong một số
tình huống đặc biệt. Chẳng hạn, các khóa mức bảng READ LOCAL cho phép một vài
kiểu ghi dữ liệu đồng thời.
Mặc dù các storage engine có thể quản lí các khóa của riêng nó nhưng bản thân

MySQL cũng sử dụng các khóa mức bảng cho nhiều mục đích. Chẳng hạn, một máy
chủ sử dụng một khóa mức bảng cho câu lệnh ALTER TABLE, không liên quan tới
storage engine.
Các khóa mức dòng (Row lock): triển khai khóa trên phạm vi từng dòng, là kiểu
khóa cung cấp tính đồng thời nhất (và mang lại chi phí tốt nhất). Khóa mức dòng là
một chiến lược được sử dụng phổ biến trong InnoDB, Falcon, và một số storage
engine khác. Các khóa mức dòng được triển khai trong storage engine, chứ không phải
trên máy chủ. Hầu hết các storage engine thực thi khóa theo cách riêng và máy chủ
hoàn toàn không hay biết về cách thức triển khai các khóa này.
1.4.3. Giao tác
Một giao tác là một tập hợp các truy vấn SQL được coi như một đơn vị công việc
đơn lẻ. Nếu một máy CSDL có thể thực thi toàn bộ các câu truy vấn bên trong, giao
tác thành công. Ngược lại, nếu có bất kì truy vấn nào trong chúng không thể được thực
hiện bởi vì một đổ vỡ hay một nguyên nhân khác, không có câu lệnh nào trong số
chúng được thực hiện. Giao tác có nghĩa hoặc là tất cả hoặc không gì cả.
Mô hình ACID: Các giao tác tuân thủ mô hình ACID. ACID viết tắt của
Atomicity, Consistency, Isolation, và Durability. Chúng là tiêu chuẩn quan hệ chặt chẽ
mà một hệ thống xử lí giao tác tốt phải đạt được:
Atomicity (tính nguyên tử)
Một giao tác phải có chức năng như là một đơn vị công việc độc lập không thể
chia nhỏ để toàn bộ giao tác hoặc được chấp nhận (commit) hoặc khôi phục lại
(rollback). Giao tác không thể hoàn thành một phần: hoặc là tất cả hoặc không gì cả.
Consistency (tính nhất quán)


19

Đảm bảo CSDL luôn luôn chuyển từ một trạng thái nhất quán này sang một trạng
thái nhất quán khác.
Isolation (tính cách ly)

Kết quả của một giao tác không thể nhìn thấy bởi một giao tác khác cho đến khi
giao tác đó hoàn thành.
Durability (độ bền)
Ngay sau khi commit, các thay đổi trong một giao tác là vĩnh viễn. Nghĩa là những
thay đổi này sẽ không bị mất trong những đổ vỡ hệ thống. Tuy nhiên độ bền là một
khái niệm mờ, bởi vì thực tế nó có rất nhiều mức độ khác nhau. Một vài chiến lược độ
bền cung cấp một đảm bảo an toàn mạnh hơn những chiến lược khác, và không có
chiến lược nào đảm bảo bền vững 100%.
Máy chủ CSDL muốn đảm bảo ACID phải thực hiện rất nhiều thứ phức tạp. Ngay
khi tăng phạm vi khóa, để đảm bảo an ninh thì máy chủ CSDL phải thực hiện nhiều
việc hơn. Một máy chủ CSDL với các giao tác ACID cũng thường yêu cầu cấu hình
CPU cao hơn, cần nhiều bộ nhớ trong và không gian đĩa hơn các máy chủ không chứa
các giao tác ACID. MySQL quản lí giao tác trong các storage engine. Việc sử dụng
các storage engine với tính tra lắp được khiến cho người dùng có thể linh hoạt quyết
định khi nào ứng dụng cần tới các giao tác. Nếu không thực sự cần, nên sử dụng một
storage engine không hỗ trợ giao tác hoặc sử dụng các bảng khóa (LOCK TABLE) để
đạt được mức bảo vệ cần thiết.
Các mức độ cách ly: Chuẩn SQL định nghĩa 4 mức độ cách ly với các luật về
việc có thể nhìn thấy hay không nhìn thấy bên trong và bên ngoài một giao tác. Mức
cách ly thấp hơn cho phép tính đồng thời cao hơn và có chi phí thấp hơn.
Các mức độ cách ly được liệt kê theo thứ tự từ thấp đến cao, gồm:
READ UNCOMMITED: tại mức này, các giao tác có thể nhìn thấy kết quả của các
giao tác không được commit. Ít được sử dụng trong thực tế do hiệu quả không cao.
Phép đọc dữ liệu chưa được commit được gọi là “dirty read”.
READ COMMITED: là mức cách ly mặc định cho hầu hết các hệ CSDL (nhưng
không phải cho MySQL). Tại mức này, một giao tác sẽ chỉ nhìn thấy những thay đổi
của các giao tác đã được commit, và những thay đổi của nó không thể được nhìn thấy
bởi các giao tác khác cho đến khi nó được commit. Mức này thường được gọi là đọc
không lặp lại (nonrepeatable read), nghĩa là nếu thực hiện cùng một câu lệnh 2 lần thì
dữ liệu nhìn thấy sẽ khác nhau.

REPEATABLE READ: đảm bảo trong một giao tác, các dòng được đọc là như
nhau với mọi thao tác đọc. Một vấn đề xảy ra ở mức cách ly này là: đọc ma - phantom
read. Một phantom read có thể xảy ra khi xem các dòng, một giao tác khác chèn một


20

dòng mới vào chính các dòng đó và sau đó lại xem lại chúng; Như vậy bạn sẽ nhìn
thấy một dòng “ma” (“phantom”) mới. Để giải quyết vấn đề này, InnoDB và Falcon sử
dụng kĩ thuật quản lí đồng thời đa phiên bản. REPEATABLE READ là mức cách ly
mặc định trong MySQL. Tuy nhiên cũng có thể thay đổi các thiết đặt đó ở mức storage
engine.
SERIALIZABLE: là mức cách ly cao nhất. Nó có thể xử lí vấn đề đọc phantom
bằng cách buộc các giao tác phải sắp thứ tự để chúng không thể xung đột.
SERIALIABLE đặt một khóa trên mọi dòng nó đọc. Là mức cách ly ít được sử dụng.
Deadlocks: Khi hai hay nhiều giao tác cùng giữ và yêu cầu khóa trên cùng một tài
nguyên, tạo ra một vòng lặp vô hạn, deadlock xảy ra. Xét hai giao tác đang trên bảng
StockPrice như sau:
Transaction #1
START TRANSACTION;
UPDATE StockPrice SET close = 45.50 WHERE stock_id = 4;
UPDATE StockPrice SET close = 19.80 WHERE stock_id = 3;
COMMIT;
Transaction #2
START TRANSACTION;
UPDATE StockPrice SET high = 20.12 WHERE stock_id = 3;
UPDATE StockPrice SET high = 47.20 WHERE stock_id = 4;
COMMIT;
Nếu mỗi giao tác thực thi truy vấn đầu tiên của nó trước và chỉnh sửa một dòng dữ
liệu, Cả 2 giao tác sẽ yêu cầu khóa, cụ thể giao tác 1 sẽ khóa bản ghi có stock_id = 4

và giao tác 2 sẽ khóa bản ghi có stock_id = 3. Sau đó, mỗi giao tác sẽ cố gắng chỉnh
sửa dòng thứ 2, nhưng lúc này cả 2 dòng đều đã bị khóa. Khi đó, cả 2 giao tác sẽ đợi
giao tác kia thực hiện xong và trừ khi có cái gì can thiệp, chúng sẽ đợi mãi mãi.
Các hệ CSDL đã sử dụng rất nhiều cách phát hiện deadlock khác nhau. Một số hệ
thống tinh vi hơn, như là InnoDB, có thể nhận ra vòng lặp vô hạn và đưa ra một thông
báo lỗi. Một số hệ thống khác lại sử dụng timeout như là một giải pháp. Các giao tác
sẽ kết thúc nếu một truy vấn vượt quá thời gian đợi (timeout) của khóa.
Thứ tự và cách thức khóa phụ thuộc vào từng storage engine, cho nên một
deadlock có thể xảy ra trong chuỗi câu lệnh của storage engine này nhưng vẫn chuỗi
câu lệnh đó trong storage engine khác thì không. Một số deadlock là không thể tránh
khỏi bởi vì dữ liệu thực sự xung đột nhưng một số khác có thể là do cách thức hoạt
động của storage engine.
Khi phá vỡ deadlock, các giao tác thường bị rollback, một phần hoặc toàn bộ.
Lưu biên bản giao tác: khiến cho giao tác được thực hiện hiệu quả hơn. Thay vì
chỉnh sửa bảng trên đĩa mỗi lần có thay đổi xảy ra, storage engine có thể chỉnh sửa trên
bản sao dữ liệu trong bộ nhớ trong của nó. Sau đó, storage engine ghi một bản ghi


21

những thay đổi lên một biên bản giao tác nằm trên đĩa. Cuối cùng, tại một thời điểm
sau đó, tiến trình có thể chỉnh sửa bảng trên đĩa. Như vậy vừa giảm được thời gian và
số lần truy cập đĩa lại vừa có tính bền vững do những thay đổi vẫn được ghi trên đĩa.
Điều này cũng cho quá trình xử lí nhanh hơn vì thay vì truy cập ngẫu nhiên trên nhiều
nơi thì có thể truy cập tuần tự trên một vùng nhỏ. Hầu hết các storage engine sử dụng
kỹ thuật này.
Nếu có một đổ vỡ sau khi một chỉnh sửa được ghi lên một biên bản giao tác nhưng
trước khi những thay đổi đó được tạo thành dữ liệu, storage engine có thể vẫn khôi
phục được những thay đổi khi khởi động lại. Phương thức khôi phục giữa các storage
engine là khác nhau.

Giao tác trong MySQL: MySQL AB cung cấp các storage engine hỗ trợ giao tác
như InnoDB, NDB cluster, Falcon,… Một vài engine bên thứ ba cũng hỗ trợ giao tác
như solidDB và PBXT.
Mặc định, MySQL được thực thi trong cơ chế autocommit =1 (hay ON). Điều đó
có nghĩa là, giao tác sẽ tự động thực hiện mỗi truy vấn độc lập.
Nếu AUTOCOMMIT = 0 (hay OFF), giao tác được thực thi cho đến khi được
COMMIT hoặc ROLLBACK. Sau đó MySQL bắt đầu ngay một giao tác mới.
Trộn các storage engine trong các giao tác: Trong MySQL, các giao tác được
thực thi ở các storage engine mà không được quản lí ở máy chủ. Do đó, không thể trộn
các storage engine khác nhau trong một giao tác.
Khóa ngầm định và tường minh: InnoDB sử dụng giao thức khóa 2 pha. Chúng
có thể đạt được khóa bất kì thời điểm nào trong một giao tác, nhưng không thể giải
phóng khóa cho đến khi được COMMIT hoặc ROLLBACK. Các khóa được giải
phóng toàn bộ tại cùng thời điểm. Đây là cơ chế khóa ngầm định và được InnoDB
quản lí tự động. Ngoài ra nó cũng hỗ trợ khóa tường minh, thứ mà chuẩn SQL không
hề đề cập đến, như là các khóa trên các bảng sẽ có yêu cầu khóa tiếp theo.
Trong MySQL, giao tác được triển khai trong các storage engine. Giao tác có thể
là một yếu tố quyết định tới việc lựa chọn một storage engine phù hợp với ứng dụng.
Mặc dù MySQL cũng hỗ trợ câu lệnh LOCK TABLES và UNLOCK TABLES được
thực thi trên máy chủ nhưng chúng không thể thay thế cho giao tác. Do đó, nếu một
ứng dụng thật sự cần giao tác, hãy lựa chọn một storage engine hỗ trợ giao tác.
1.4.4. Điều khiển đồng thời đa phiên bản (MVCC)
Hầu hết các storage engine hỗ trợ giao tác trong MySQL, như là InnoDB, Falcon,
và PBXT không sử dụng một cơ chế khóa mức dòng đơn giản. Thay vào đó, chúng sử
dụng khóa mức dòng trong sự kết hợp với một kĩ thuật để gia tăng tính đồng thời gọi
là điều khiển đồng thời đa phiên bản (Multiversion Concurrency Control – MVCC).


22


Không chỉ MySQL, một số hệ CSDL khác như là Oracle, PostgreSQL, … cũng sử
dụng kĩ thuật này.
Điều khiển đồng thời đa phiên bản (MVCC) có thể coi là cải tiến của khóa mức
dòng. Nó tránh việc khóa tất cả các tài nguyên và trong nhiều trường hợp có thể đem
lại chi phí thấp hơn nhiều. Phụ thuộc vào cách triển khai, nó có thể cho phép đọc
không khóa, trong khi chỉ khóa những bản ghi cần thiết khi thực hiện thao tác ghi.
MVCC hoạt động bằng cách giữ một snapshot của dữ liệu của một vài thời điểm.
Do đó, giao tác có thể nhìn thấy dữ liệu nhất quán mà không quan tâm tới chúng đã
thực thi bao lâu. Điều đó cũng có nghĩa là các giao tác khác nhau có thể nhìn thấy
những dữ liệu khác nhau trong cùng một bảng tại cùng một thời điểm. Các storage
engine khác nhau triển khai điều khiển đồng thời đa phiên bản khác nhau.
1.4.5. Chỉ mục
Chỉ mục là cấu trúc dữ liệu hỗ trợ MySQL tìm kiếm dữ liệu một cách hiệu quả.
Chỉ mục (đôi khi còn gọi là “khóa”) càng quan trọng khi dữ liệu càng lớn. Những cơ
sở dữ liệu nhỏ có thể đạt hiệu suất tốt ngay cả khi không có chỉ mục nhưng khi dữ liệu
lớn hơn thì hiệu suất giảm một cách nhanh chóng. MySQL thường triển khai các cơ
chế chỉ mục trong các storage engine. Hơn nữa, cách triển khai chúng trong từng
storage engine là không giống nhau: các storage engine khác nhau triển khai những
kiểu chỉ mục khác nhau; không phải mọi engine đều hỗ trợ mọi loại chỉ mục; thậm chí
khi nhiều engine hỗ trợ cùng một loại chỉ mục thì sự triển khai chúng cũng không
giống nhau. Mặc dù các kiểu chỉ mục trong storage engine là vô cùng phong phú
nhưng vẫn có một số kiểu chỉ mục thường được hỗ trợ. Sau đây là một số loại chỉ mục
như thế:
Các chỉ mục B-Tree: tất cả các giá trị được lưu trữ theo thứ tự, mỗi trang lá có
cùng khoảng cách tới gốc. Mỗi nút chứa dữ liệu của nó cùng với con trỏ tới con của
nó. Quá trình tìm kiếm diễn ra từ gốc và tìm kiếm trên cây dựa trên khóa tìm kiếm. Nó
khiến cho quá trình tìm kiếm diễn ra nhanh chóng mà không phải thăm toàn bộ bảng
để tìm dữ liệu. Thay vào đó, bắt đầu từ gốc, đi theo các con trỏ tới các nút con thỏa
mãn điều kiện nào đó (ví dụ như key >value hoặc <=value) cho đến khi tìm thấy lá cần
tìm hoặc khẳng định rằng giá trị đó không tồn tại.

Một cải tiến khác của B-Tree là B+Tree. Khi đó, tại mỗi nút bổ sung thêm con trỏ
trỏ tới nút liền kề với nó, khiến cho quá trình tìm kiếm nhanh hơn.
Hầu hết các storage engine của MySQL sử dụng chỉ mục B-Tree. Tuy nhiên, cách
thức lưu trữ trên đĩa không giống nhau dẫn tới hiệu suất đạt được có thể khác nhau. Ví
dụ như: MyISAM sử dụng kĩ thuật nén tiền tố khiến cho các chỉ mục nhỏ hơn, trong
khi InnoDB lại không sử dụng vì chúng không phù hợp với chiến lược tối ưu hóa của
InnoDB. Các chỉ mục MyISAM tham chiếu tới các dòng bằng vị trí vật lí của dòng đó


23

nhưng InnoDB tham chiếu thông qua các giá trị khóa chính. Mỗi cách làm có những
lợi ích và hạn chế riêng.
Chỉ mục băm (hash index): được xây dựng trên các bảng băm và chỉ hữu ích cho
các tìm kiếm chính xác sử dụng cho mọi cột trong chỉ mục đó.
Tại mỗi dòng, các storage engine tính toán một mã băm của các cột chỉ mục. Nó
lưu trữ các mã băm trong chỉ mục và lưu trữ một con trỏ tới mỗi dòng của bảng băm
đó.
Chỉ mục tiền tố (Prefix index): được sử dụng trong trường hợp phải lập chỉ mục
trên các cột có rất nhiều kí tự khiến cho chỉ mục lớn và chậm mà không thể dùng chỉ
mục băm được.
Giải pháp đưa ra là lập chỉ mục trên một vài kí tự đầu tiên thay vì trên toàn bộ giá
trị. Điều đó khiến các chỉ mục sử dụng ít không gian hơn nhưng đồng thời cũng ít tính
chọn lọc hơn. Tính chọn lọc của chỉ mục là tỉ số của số khoảng cách các giá trị chỉ
mục trên tổng số dòng trên bảng (#T) và nằm trong khoảng từ 1/#T đến 1. Một chỉ
mục có tính lựa chọn cao sẽ khiến cho MySQL lọc nhiều dòng hơn khi tìm kiếm.
Tiền tố của cột thường được lựa chọn để đạt được hiệu suất đủ tốt. Đối với các cột
dữ liệu kiểu TEXT, BLOB hay các cột VARCHAR rất dài, phải sử dụng chỉ mục tiền
tố vì MySQL không cho phép lập chỉ mục trên toàn bộ độ dài của chúng.
Hạn chế là phải lựa chọn tiền tố đủ dài để đạt hiệu suất cao đồng thời phải đủ ngắn

để hạn chế không gian. Tiền tố nên đủ dài để khiến cho chỉ mục có tính hữu dụng gần
như là khi lập chỉ mục trên toàn bộ cột.
Chỉ mục cụm (clustered index): không phải là một kiểu chỉ mục, đó là một
hướng tiếp cận lưu trữ dữ liệu. Khi một bảng có một chỉ mục cụm, các dòng của nó
thực tế được lưu trữ trên các lá, các nút khác chỉ chứa các cột chỉ mục. Thuật ngữ
“phân cụm” để chỉ rằng các dòng với các giá trị khóa liền kế được lưu trữ gần nhau.
Trên mỗi bảng chỉ có thể có duy nhất một chỉ mục cụm do không thể lưu trữ các dòng
tại 2 nơi cùng lúc được.
Lợi ích của chỉ mục cụm:
 Lưu trữ các dữ liệu liên quan gần nhau
 Truy cập dữ liệu nhanh hơn. Một chỉ mục cụm giữ cả chỉ mục và dữ liệu trong
một cấu trúc B-Tree, vì thế khi tìm kiếm các dòng từ một chỉ mục cụm thường
nhanh hơn so với các trường hợp khác.
Chỉ mục cuộn (covering index): Các truy vấn sử dụng các chỉ mục cuộn sử dụng
các giá trị khóa chính chứa tại các nút lá. Chỉ mục là một cách để tìm kiếm các dòng
một cách hiệu quả, nhưng MySQL cũng có thể sử dụng một chỉ mục để tìm kiếm dữ
liệu trong một cột, vì thế nó không cần phải đọc dòng đó. Các nút lá chứa giá trị mà


24

chúng chỉ mục. Một chỉ mục chứa tất cả dữ liệu cần thiết thỏa mãn một truy vấn gọi là
chỉ mục cuộn.
Chỉ mục gói (hay chỉ mục nén tiền tố): để giảm kích thước chỉ mục, cho phép
nhiều chỉ mục hơn phù hợp với bộ nhớ trong và cải thiện đáng kể hiệu suất trong một
số trường hợp.
MyISAM gói mỗi khối chỉ mục bằng cách lưu trữ đầy đủ giá trị đầu tiên của khối,
sau đó lưu trữ mỗi giá trị bổ sung trong khối đó bằng cách ghi số lượng các byte có
cùng tiền tố và dữ liệu khác nhau của hậu tố. Ví dụ, nếu giá trị đầu tiên là “perform”
và giá trị thứ hai là “performance” thì giá trị thứ 2 được lưu trữ là “7,ance”.

Các khối nén sử dụng ít không gian hơn nhưng nó cũng làm quá trình thực thi lâu
hơn. Bởi vì mỗi tiền tố nén của giá trị phụ thuộc vào giá trị trước nó.
Kết luận chương 1: MySQL là một hệ quản trị cơ sở dữ liệu mã nguồn mở phổ
biến nhất hiện nay. MySQL sử dụng kiến trúc tương đồng với nhiều hệ quản trị CSDL
quan hệ khác đồng thời cũng đưa ra một số giải pháp nổi bật như là triển khai nhiều bộ
đệm (bộ đệm truy vấn, bộ đệm bảng, bản ghi,…), và đặc biệt là sử dụng kiến trúc
pluggable storage engine độc đáo cho phép triển khai một cách linh hoạt các phương
thức quản lí đồng thời, hỗ trợ giao tác, điều khiển đồng thời đa phiên bản và hỗ trợ chỉ
mục riêng độc lập với máy chủ. Điều đó khiến cho MySQL được đánh giá là một hệ
QTCSDL có tính linh hoạt cao, đáp ứng được nhiều nhu cầu khác nhau của nhiều
người dùng.

×