trong MySQL hay các hệ quản trị cơ sở dữ liệu khác là cách lưu trữ luận lý nhằm giúp người dùng có thể dễ dàng hiểu và sử dụng cơ sở dữ liệu.. Cấu trúc chỉ mục Clustered index
Trang 1BỘ GIÁO DỤC VÀ ĐÀO TẠO TRƯỜNG ĐẠI HỌC BÁCH KHOA TPHCM
BÀI TẬP LỚN
HỆ QUẢN TRỊ CƠ SỞ DỮ LIỆU
MySQL & Cassandra
GVHD: Võ Thị Ngọc Châu Nhóm: 5
Trang 2Mục Lục
I Lựa chọn cấu trúc lưu trữ cho tập tin dữ liệu 3
1 MySQL 3
1.1 Inno DB 3
1.2 Các dữ liệu trong MySQL 5
2 Cassandra 8
2.1 Cấu trúc chung của Cassandra 8
II Thực hành với chỉ mục 14
1 MySQL 14
1.1 Lý thuyết về các dạng chỉ mục 14
1.2 Cấu trúc chỉ mục 14
1.3 Ví dụ minh họa 18
2 Cassandra 19
2.1 Lý thuyết về các dạng chỉ mục 19
2.2 Cấu trúc chỉ mục 22
2.3 Kd – tree: 23
2.4 Ví dụ minh họa 24
3 Tổng kết 25
III Tính năng phục hồi dữ liệu 26
1 Lý thuyết 26
1.1 MySql 26
1.2 Cassandra 27
2 Ứng dụng vào thực hành 27
2.1 Restore data trong mysql sử dụng xampp trên ubuntu 27
2.2 Restore database trong cassandra 30
IV Tính năng sao lưu dữ liệu 35
1 SQL 35
1.1 Tóm tắt lý thuyết 35
1.2 Thực hành 35
2 Cassandra 38
2.1 Cơ sở lí thuyết 38
2.2 Thực hành 40
V Tổng kết 41
VI Phân chia công việc 41
Trang 3I Lựa chọn cấu trúc lưu trữ cho tập tin dữ liệu
1 MySQL
MySQL là một hệ thống quản trị cơ sở dữ liệu mã nguồn mở (gọi tắt là RDBMS) hoạt động theo mô hình client-server ới RDBMS là viết tắt của Relational Database Management System MySQL được tích hợp apache, PHP MySQL quản lý dữ liệu thông qua các cơ sở dữ liệu Mỗi cơ sở dữ liệu có thể có nhiều bảng (table) quan hệ chứa nhiều bản ghi (record), mà mỗi record gồm nhiều trường dữ liệu (field) MySQL cũng có cùng một cách truy xuất và mã lệnh tương
tự với ngôn ngữ SQL Trong mô hình ERD thì bảng tương ứng với một thực thế (entity) và các dữ liệu là các thuộc tính của thực thể đó
Theo mặc định, các record sẽ được sắp xếp vật lý dưới đĩa (disk) dựa trên PRIMARY KEY INDEX
Dạng lưu trữ hàng, cột, bảng trong MySQL hay các hệ quản trị cơ sở dữ liệu khác là cách lưu trữ luận lý nhằm giúp người dùng có thể dễ dàng hiểu và sử dụng cơ sở dữ liệu Tuy vậy, muốn hiểu việc MySQL lưu trữ dữ liệu trên ổ cứng như thế nào thì t cần hiểu đến khái niệm Storage Engine Storage Engine là cách MySQL lưu trữ dữ liệu trên đĩa cứng MySQL lưu mỗi database như là một thư mục con nằm dưới thư mục data Khi một table được tạo ra., MySQL sẽ lưu định nghĩa bảng ở file đuôi frm và tên trùng với tên của bảng được tạo Ta sẽ tiến hành đi tìm hiểu một Storage Engine được sử dụng phổ biến cùng với MySQL: InnoDB
1.1 Inno DB
Một bản ghi vật lý cảu MySQLsử dụng Storage Engine InnoDB sẽ gồm có 3 phần : Field Start Offsets, Extra Bytes, Field Contents
Field Start Offsets (F*1) or (F*2) (F: số field của
record)
Field Contents Tùy vào giá trị của field
Các bản ghi sẽ được lưu trữ vật lí vào một đơn vị, được gọi là “page” hoặc
“block” Một page có độ dài cố dịnh là 16KB Một page gồm có 7 phần tử được sắp xếp theo thứ tự như sau: Fill Header, Page Header, Infimum + Supermum Records, User Records, Free Space, Page Directory, Fill Trailer Có thể thấy ở phần giữa của page là các record chứa dữ liệu và khoảng rỗng free space dùng
để chèn các record mới vào
Trang 4Trong nội dung bài báo cáo này, nhóm sẽ trình abỳ chi tiết hơn về cấu trúc lưu trữ vật lí cảu bản ghi (record)
a) Field Start Offsets
- Về cơ bản, phần này gồm những thông tin về địa chỉ bắt đầu của một trường dữ liệu
- Giả sử có một record có 3 field: Field 1, Field 2, Field 3 có độ dài lần lượt là 1, 2, 3 Các giá trị offset của các trường sẽ lần lượt là: 1, 3, 6 Các giá trị này được lưu theo chiều ngược lại và dưới dạng nhị phân: 06, 03, 01
b) Extra bytes:
- Là header gồm có 6 bytes (fixed-size, 48 bits)
of index’s page
record
1 byte_off_flag 1 1 if length oif Filed
Start Offsets = 1 byte Next 16 bits 16 Pointer to next record
+ Điểm bắt đầu của record ở địa chỉ pointer value – X
Type=InnoDB;
Trang 5- Bảng T thực chất được tạo ra với 6 cột InnoDB tự động thêm vào 3 "cột
hệ thống" vào đầu để quản lí 3 cột này lần lượt là row ID, transaction ID
và rollback pointer
- Tiếp theo, Thêm vào bảng một vài record:
INSERT INTO T VALUES (’PP’, ’PP’, ’PP’);
INSERT INTO T VALUES (’Q’, ’Q’, ’Q’);
INSERT INTO T VALUES (’R’, NULL, NULL);
- Khi đó, giá trị nhị phân được lưu dưới đĩa cứng sẽ như sau:
19 17 15 13 0C 06 Field Start Offsets /* First Row */
1.2 Các dữ liệu trong MySQL
a) Các kiểu số nguyên
Các kiểu số nguyên tiêu chuẩn của SQL như INTEGER (or INT) và SMALLINT đều được hỗ trợ bởi MySQL Và các mở rộng tiêu chuẩn, MySQL cũng hỗ trợ các kiểu số nguyên khác như TINYINT, MEDIUMINT, và BIGINT Bảng dưới đây sẽ liệt kê các kiểu và không gian lưu trữ đòi hỏi và phạm vi của chúng (Giá trị nhỏ nhất, lớn nhất cho kiểu số nguyên có dấu, và không dấu)
Type Length(byte) Min val(Signed) Max val(Signed)
Trang 6b) Kiểu dấu chấm động (Floating-Point Types)
Kiểu dữ liệu FLOAT và DOUBLE mô tả gần đúng các giá trị số thực MySQL sử dụng 4 byte để lưu trữ dữ liệu FLOAT và 8 byte dành cho kiểu dữ liệu DOUBLE
- FLOAT(M,D): Một số chấm động (floating-point number) không thể không có dấu (unsigned) Có thể định nghĩa độ dài phần nguyên (M) và
độ dài phần thập phân (D) Điều này không bắt buộc và mặc định là 10,2,
ở đây 10 là độ dài phần nguyên còn 2 là số số thập phân Phần thập phân
có thể sử dụng 24 vị trí cho một số FLOAT
- DOUBLE(M,D): Một số chấm động DOUBLE (Độ chính xác gấp 2) cũng không thể không có dấu (unsigned) Có thể định nghĩa độ dài phần nguyên (M) và độ dài phần thập phân
- D) Điều này không bắt buộc và mặc định là 16,4, ở đó 16 là độ dài phần nguyên còn 4 là độ dài phần thập phân Phần thập phân có thể sử dụng tới
53 vị trí cho một số DOUBLE REAL là một từ đồng nghĩa với DOUBLE
c) Kiểu dấu chấm cố định (Fixed-Point Types)
Kiểu dấu chấm cố định (Fixed-Point data type) được sử dụng để bảo vệ
độ chính xác (precision), ví dụ như với dữ liệu tiền tệ Trong MySQL kiểu DECIMAL và NUMERIC lưu trữ chính xác các dữ liệu số MySQL 5.6 lưu trữ giá trị DECIMAL theo định dạng nhị phân
Trong SQL chuẩn, cú pháp DECIMAL(5,2) nghĩa là độ chính xác (precision) là 5, và 2 là phần thập phân (scale), nghĩa là nó có thể lưu trữ một giá trị có 5 chữ số trong đó có 2 số thập phân Vì vậy giá trị lưu trữ sẽ là -999.99 tới 999.99 Cú pháp DECIMAL(M) tương đương với DECIMAL(M,0) Tương tự DECIMAL tương đương với DECIMAL(M,0) ở đây M mặc định là 10 Độ dài tối đa các con số cho DECIMAL là 65
d) Kiểu dữ liệu DATETIME, DATE, và TIMESTAMP
- DATETIME: Sử dụng khi cần giá trị lưu trữ cả hai thông tin ngày tháng
và thời gian Ví dụ: 2020-03-20 07:30:45
- DATE: Sử dụng khi muốn lưu trữ chỉ thông tin ngày tháng Ví dụ: 03-20
2020-• TIMESTAMP: Lưu trữ cả hai thông tin ngày tháng và thời gian Giá trị này sẽ được chuyển đổi từ múi giờ hiện tại sang UTC trong khi lưu trữ,
và sẽ chuyển trở lại múi giờ hiện tại khi lấy dữ liệu ra
Kiểu dữ liệu DATETIME được sử dụng khi cần lưu trữ cả hai thông tin ngày tháng và thời gian MySQL lấy và hiển thị DATETIME theo định
Trang 7dạng ‘YYYY-MM-DD HH:MM:SS’ Và hỗ trợ phạm vi từ ’1000-01-01 00:00:00’ tới ’9999-12-31 23:59:59’
Kiểu dữ liệu TIMESTAMP cũng được sử dụng khi muốn lưu trữ cả hai thông tin ngày tháng và thời gian TIMESTAMP có phạm vi ’1970-01-01 00:00:01’ UTC tới ’2038-01-19 03:14:07’ UTC
Sự khác biệt chính của DATETIME và TIMESTAMP là giá trị của TIMESTAMP được chuyển đổi từ múi giờ hiện tại sang UTC trong khi lưu trữ, và chuyển ngược trở lại từ UTC sang múi giờ hiện tại trong lúc lấy ra Còn kiểu dữ liệu DATETIME thì không có gì thay đổi
e) Kiểu dữ liệu CHAR và VARCHAR
Các field có thể được chia ra làm 2 loại: fixed-length và variable-length (độ dài cố định và độ dài biến đổi) Chẳng hạn đối với MySQL, một field với type INT sẽ có độ dài cố định là 4-byte Hoặc CHAR với độ dài cố định do người dùng định nghĩa (0-255 bytes), DBMS sẽ lưu dữ liệu dạng CHAR bằng cách right-padding khoảng trắng để bù cho đủ độ dài định nghĩa trên
Tuy vậy khi truy xuất dữ liệu khoảng trắng sẽ bị bỏ đi Còn field với type VARCHAR thì sẽ có độ dài thay đổi (Tuy vậy độ dài tối đa vẫn được định nghĩa trước, dao động cũng trong khoảng 0-255) VARCHAR sẽ có 1 byte prefix để lưu trữ độ dài của giá trị
Hình 1: Ví dụ về lưu trữ dữ liệu theo kiểu CHAR
Trang 8Hình 2: Ví dụ về lưu trữ dữ liệu theo kiểu VARCHAR
f) Kiểu dữ liệu BLOB
BLOB là một đối tượng nhị phân lớn (Binary Large OBject) có thể chứa một lượng lớn dữ liệu Có bốn loại BLOB, TINYBLOB, BLOB, MEDIUMBLOB, và LONGBLOB Nhưng chỉ khác nhau về độ dài tối đa của các giá trị có thể giữ Kiểu dữ liệu BLOB thường được dùng để lưu trữ dữ liệu dưới dạng hình ảnh
2.1 Cấu trúc chung của Cassandra
Cassandra là một hệ quản trị cơ sở dữ liệu phân tán (NoSQL)
Cơ sở dữ liệu Cassandra được phân tán trên nhiều máy hoạt động với nhau (cluster) Cassandra sắp xếp các nút trong một cluster theo định dạng vòng
và gán dữ liệu cho chúng
Keyspace là vỏ bọc ngoài cùng cho dữ liệu trong Cassandra, là một kho chứa các Column Family Tất cả dữ liệu của Cassandra được đặt trong Keyspace nên có thể tạo một Keyspace duy nhất cho tất các các Column Family Các thuộc tính cơ bản của keyspace trong Cassandra bao gồm:
o Yếu tố nhân rộng (Replication factor): là số lượng máy trong một cluster sẽ nhậnđược các bản sao của cùng một dữ liệu
Trang 9o Chiến lược đặt bản sao (Replica placement strategy): chiến lược
để đặt bản sao trong vòng (chiến lược đơn giản , chiến lược cấu trúc , chiến lược liên kết mạng)
Hình 3: Hình ảnh minh họa cấu trúc Keyspace
Dữ liệu được lưu trữ trong DB của Cassandra thuộc dạng Key value store (KVS)
Mô hình dữ liệu Cassandra tuân theo quy tắc hệ thống cột (the column family):
Trang 10- Column Family: là một đối tượng của NoSQL nơi chứa các cột dữ liệu
Nó là một tập hợp dữ liệu chứa các cặp “khóa – giá trị” Trong đó “khóa” được ánh xạ đến một giá trị gồm tập hợp các cột Tương tự với RDBMS, column family là một bảng, mỗi cặp “khóa – giá trị” là một hàng
Hình 4: Hình ảnh minh họa cấu trúc Column family
- Cột là một tập hợp dữ liệu (bộ 3) gồm tên cột, giá trị, và mốc thời gian
Hình 5: Hình ảnh minh họa cấu trúc Column
- Siêu cột một cột đặc biệt lưu trữ bản đồ (map) của các cột Nó giúp lưu trữ cũng như truy xuất dữ liệu dễ dàng và nhanh chóng hơn
Hình 6: Hình ảnh minh họa cấu trúc siêu cột
2.1 Các kiểu dữ liệu trong Cassandra
Trang 11a) Các kiểu dữ liệu cơ bản
- ascii: Biểu diễn cho một chuỗi ký tự ASCII Việc chèn bất kỳ ký tự không phải ASCII vào một cột của kiểu dữ liệu này sẽ cho ra một lỗi
- bigint: Đại diện cho số nguyên có dấu dài 64-bit Được sử dụng để lưu trữ những con số dài Nó nên được sử dụng chỉ khi chúng ta chắc chắn cần các số dài vì nó chiếm nhiều không gian bộ nhớ hơn so với int
- blob: dùng để lưu trữ các byte tuỳ ý Nó ở hệ thập lục phân, và bất kỳ dữ liệu nào không cần xác nhận có thể được lưu trữ trong trường này
- boolean: Lưu trữ true hoặc false
- counter: Đại diện cho một số nguyên dài 64-bit, nhưng giá trị của cột này không thể thiết lập Chỉ có hai hoạt động trên cột này, tăng và giảm Trong một bảng với một cột counter, chỉ có các kiểu counter và khóa chính là được phép Không có câu lệnh INSERT được phép trong một bảng với các column counter; chỉ UPDATE có thể được sử dụng Ví dụ:
> CREATE TABLE website_tracker (
id int PRIMARY KEY,
- date: Đại diện cho một giá trị ngày mà không có một giá trị giờ Cassandra
mã hóa giống như một giá trị số nguyên kể từ epoch Ngày có thể được biểu diễn như là chuỗi trong định dạng yyyy-mm-dd
- decimal: Đại diện cho một biến-giá trị thập phân chính xác Dùng tốt nhất trong việc lưu trữ tiền tệ hoặc các giá trị tài chính
- double: Lưu trữ một giá trị dấu chấm động dài 64-bit
- float: Lưu trữ một giá trị dấu chấm động 32-bit
- inet: Biểu diễn cho một chuỗi địa chỉ IP trong định dạng của IPv4 hoặc IPv6
- int: Biểu diễn cho một số nguyên có dấu dài 32-bit Sử dụng chủ yếu để lưu trữ các giá trị số nguyên
- smallint: Biểu diễn cho một số nguyên 2 byte (16-bit) Có thể được ưu tiên hơn so với kiểu int để lưu trữ các giá trị số nguyên nhỏ để tiết kiệm không gian lưu trữ
Trang 12- text: Biểu diễn cho một chuỗi mã hoá UTF-8 Nên được sử dụng khi chúng ta muốn lưu trữ các ký tự không phải mã ASCII
- time: Biểu diễn cho một giá trị thời gian Đại diện như một chuỗi ở dạng 01:02:03.123 và
- lưu trữ số nguyên có dấu dài 64-bit đại diện cho số nano giây trôi qua kể
từ nửa đêm
- timestamp: Lưu trữ cả thành phần ngày và giờ với độ chính xác milli giây
Có thể được biểu diễn dưới dạng văn bản ở định dạng 2016-12-01 01:02:03.123
- tinyint: Biểu diễn cho một số nguyên 1 byte (8 bit) Có thể được ưu tiên hơn so với kiểu int hoặc smallint để lưu trữ các giá trị số nguyên nhỏ để tiết kiệm không gian lưu trữ
- timeuuid: Lưu trữ phiên bản 1 UUID
- uuid: UUID ở định dạng chuẩn Đây là một giá trị lớn hơn so với timeuuid
- varchar: Tương tự như văn bản Cả hai có thể được sử dụng để thay thế cho nhau
- variant: Một giá trị số nguyên với độ chính xác tùy ý Nó được khuyên nên sử dụng một kiểu dữ liệu với độ chính xác cần thiết
b) Các kiểu dữ liệu tập hợp
- set: Kiểu này lưu trữ một bộ sưu tập các giá trị Các giá trị được lưu trữ không có thứ tự, nhưng CQLSH sẽ trả về dữ liệu đã được sắp xếp Ví dụ: chuỗi sẽ được sắp xếp theo thứ tự ABC
Ví dụ hãy sửa đổi bảng mà chúng ta đã tạo ra ở trên:
> ALTER TABLE website_tracker ADD tagsSet set<text>;
> UPDATE website_tracker SET tagsSet = {’tag1’} WHERE id = 1;
> SELECT tagsSet FROM website_tracker WHERE id = 1; tagsSet
- list: Một danh sách cũng lưu trữ một bộ sưu tập các giá trị nhưng lưu trữ chúng theo kiểu đã được sắp xếp, mặc định sắp theo thứ tự chèn vào Hãy
Trang 13thử làm điều tương tự như chúng ta đã làm ở trên với bộ sưu tập với một danh sách ngay bây giờ:
> ALTER TABLE website_tracker ADD tagsList list<text>;
> UPDATE website_tracker SET tagsList = [’tag1’] WHERE id = 1;
> SELECT tagsList FROM website_tracker WHERE id = 1; tagsList
> ALTER TABLE website_tracker ADD tagsMap map<text, text>;
> UPDATE website_tracker SET tagsMap = {’tag1’: ’Tag One’} WHERE id = 1;
> SELECT tagsMap FROM website_tracker WHERE id = 1; tagsMap
-{’tag1’: ’Tag One’}
> UPDATE website_tracker SET tagsMap[’tag2’] = ’Tag Two’ WHERE id = 1;
> SELECT tagsMap FROM website_tracker WHERE id = 1; tagsMap
-{’tag1’: ’Tag One’, ’tag2’: ’Tag Two’}
c) Các kiểu dữ liệu riêng
Chúng ta có thể định nghĩa các kiểu dữ liệu của riêng mình trong Cassandra Điều này tạo ra rất nhiều sự linh hoạt và dễ dàng bảo dưỡng tổng thể Giả sử chúng ta muốn lưu trữ địa chỉ đăng ký của trang web
> CREATE TYPE address (
street text,
city text,
Trang 14state text);
> ALTER TABLE website_tracker ADD reg_address address;
Để sử dụng một kiểu dữ liệu tuỳ biến trong một bộ sưu tập lồng nhau, chúng ta cần phải xác định nó như là một bộ sưu tập frozen
> ALTER TABLE website_tracker ADD reg_addresses map<text, frozen<address>>;
II Thực hành với chỉ mục
II Thực hành với chỉ mục
1 MySQL
1.1 Lý thuyết về các dạng chỉ mục
Các dạng chỉ mục mà MySQL hỗ trợ tính đến hiện nay:
UNIQUE: là chỉ mục trong đó tất cả các giá trị của cột phải là duy nhất (có thể NULL) Đối với dạng một cột (single column) thì không thể có trùng lặp giữa các giá trị trong cột được lập chỉ mục Đối với dạng nhiều cột (multi-column), các giá trị có thể giống nhau trong một cột, nhưng giá trị kết hợp giữa các cột với nhau trong mỗi hàng là duy nhất
PRIMARY KEY: là một UNIQUE nhưng các giá trị không được là NULL Mọi hàng phải có giá trị của cột hoặc giá trị của nhiều cột được kết hợp
INDEX: là chỉ mục trong đó các giá trị không cần phải là duy nhất và có thể
là NULL Chỉ mục này được thêm vào để giúp cơ sở dữ liệu truy vấn nhanh hơn
FULLTEXT: là chỉ mục được sử dụng cho các tìm kiếm toàn văn, giúp tìm khối văn bản có chứa một từ hoặc nhóm từ nhất định hoặc có thể bạn muốn tìm một chuỗi con nhất định trong khối văn bản lớn hơn Thay vì toàn bộ giá trị được lập chỉ mục, chỉ mục fulltext sẽ lập chỉ mục các từ riêng lẻ bên trong mỗi khối văn bản Điều này giúp việc tìm các từ và cụm từ cụ thể bên trong toàn bộ văn bản nhanh hơn
DESC: descending index (có sẵn trong phiên bản 8+ của MySQL) là một chỉ mục thông thường được lưu trữ theo thứ tự ngược lại Chỉ mục này rất thuận tiện cho việc truy vấn những dữ liệu được thêm vào gần đây
1.2 Cấu trúc chỉ mục
Clustered index, non-clustered index
MySQL có các lựa chọn trong kiểu cấu trúc dữ liệu để sử dụng khi tạo chỉ mục: phân cụm (clustered) hoặc không phân cụm (non-clustered)
Trong chỉ mục phân cụm (clustered index): Các record được lưu trữ trên đĩa theo cùng thứ tự với chỉ mục nên với mỗi bảng chỉ có một clustered index duy nhất Cũng nhờ tính chất đó mà clustered index thường truy vấn nhanh
Trang 15hơn vì có thể lấy tất cả thông tin từ chỉ mục mà không cần phải tham khảo từ bảng gốc
Trong chỉ mục không phân cụm (non-clustered index) thì sử dụng con trỏ tham chiếu đến dữ liệu, nghĩa là, cấu trúc của chỉ mục tách biệt với cấu trúc của các record trong bảng Và vì sự tách biệt đó nên có thể tạo nhiều non-clustered index và có thể sắp xếp lại chỉ mục mà không ảnh hưởng đến tính đúng đắn Và các tính chất trên dẫn đến việc nếu muốn truy vấn thì phải tìm chỉ mục cụ thể và dùng nó để truy vấn dữ liệu trong bảng và
có thể mất nhiều thời gian để ghi
InnoDB là một Storage Engine của MySQL, là một công cụ lưu trữ đa năng cân bằng giữa độ tin cậy và hiệu suất cao.InnoDB là Storage Engine mặc định trong nhiều phiên bản MySQL (tính đến phiên bản hiện tại 8.0) Khi tạo bảng nếu không có mệnh đề ENGINE thì bảng được tạo ra mặc định là bảng
InnoDB Mỗi bảng InnoDB có một chỉ mục đặc biệt là clustered index để lưu trữ record Thông thường thì clustered index chính là PRIMARY KEY Để có được hiệu suất tốt nhất từ các tác vụ truy vấn, chèn và các hoạt động cơ sở dữ liệu khác, điều quan trọng là phải hiểu cách InnoDB sử dụng clustered index
để tối ưu hóa các thao tác tra cứu và DML thông thường
Khi xác định PRIMARY KEY trên một bảng, InnoDB sử dụng nó làm clustered index Một khóa chính phải được xác định cho mỗi bảng
Nếu không thể xác định PRIMARY KEY cho một bảng, InnoDB sử dụng UNIQUE index đầu tiên với tất cả các cột chính được xác định là NOT NULL làm clustered index
Nếu 2 trường hợp trên không xảy ra, thì InnoDB sẽ tạo một clustered index ẩn có tên GEN_CLUST_INDEX trên một cột tổng hợp có chứa các giá trị row ID Các hàng được sắp xếp theo row ID mà InnoDB chỉ định Row ID là một trường 6 byte, và sẽ tăng khi các hàng mới được chèn vào Do đó, các hàng được sắp xếp theo row ID về mặt vật lý theo thứ tự được chèn vào
Và tất cả các loại index còn lại là non-clustered index
Như ta đã biết thì việc hiện thực chỉ mục là của storage engine, MySQL có khá đa dạng storage egine, ngoài InnoDB ở trên có thể kể thêm một số engine phổ biến như: MEMORY, MyISAM,… Mỗi engine sẽ hỗ trợ một số loại chỉ mục riêng, hay tất cả engine đều cũng có hỗ trợ một loại chỉ mục nhưng cách hiện thực của các engine là khác nhau như InnoDB sẽ sử dụng cấu trúc B-tree (thực chất là B+-tree) , MEMORY sử dụng Hash index,…
B+ – tree
Clustered index:
Trang 16Sau khi clustered index được xác định theo cách như đã trình bày ở phía trên, các giá trị của cột được chọn sẽ được InnoDB tổ chức lưu trữ theo cấu trúc B+-tree
Khác với B-tree thông thường là nút lá sẽ chứa các record pointer tham chiếu đến record thì B-tree của clustered index có các nút lá chứa toàn bộ record, tức
là chỉ cần tìm kiếm với cột được đánh clustered index thì sẽ có luôn kết quả
mà không phải tham chiếu đến nơi record đang được lưu trữ Vì những yếu tố trên nên chính xác là clustered index được InnoDB tổ chức theo cấu trúc B+-tree
No table of figures entries found.
Hình 1 B+tree của clustered index
Non-clustered index:
Đối với những index còn lại (không phải là clustered index) thì InnoDB cũng sẽ xây dựng cấu trúc B+-tree dựa trên giá trị của cột cần tạo index và ở tầng lá, thì các nút
lá sẽ chứa giá trị tương ứng của cột đã tạo clustered index
Khi thực hiện truy vấn trên cột non-clustered index, MySQL sẽ tìm kiếm trên tree index của cột đó, kết quả trả về sẽ là giá trị của cột clustered index tương ứng Sau đó, MySQL sẽ lấy giá trị đó và tiếp tục tìm kiếm trên B+-tree của clustered index trả về kết quả là một record đầy đủ thỏa yêu cầu
Trang 17B+-Hình 2 Tham chiếu từ B+-tree non-clustered index sang B+-tree clustered index
Hash Index
Hash index sử dụng kỹ thuật hashing để lưu chỉ mục trên một hash table và
tìm kiếm dữ liệu trên đó Trong MySQL, hash index chỉ được hỗ trợ bởi
engine MEMORY Các giá trị của cột được chỉ mục thông qua hash function sinh ra hash code, các hash code này được chứa trong các bucket (thùng), với mỗi hash code có chưa tham chiếu đến record của giá trị được chỉ mục Nếu hash index được tạo trên cột non-UNIQUE, các giá trị giống nhau sẽ được lưu các con trỏ tham chiếu đến record trong cùng 1 entry
Hash index chỉ được sử dụng trong các truy vấn có điều kiện bằng ‘=’ với tốc
độ rất nhanh, nhưng với các truy vấn với các điều kiện khác như <, >,… thì
không thể
Trình tối ưu hóa không thể sử dụng Hash index để tăng tốc các thao tác
ORDER BY vì không thể tìm kiếm mục tiếp theo theo thứ tự
Trang 18Hình 3 Ví dụ về cấu trúc Hash index
1.3 Ví dụ minh họa
Ta sử dụng Sakila Sample Database (https://dev.mysql.com/doc/sakila/en/) được cung cấp bởi trang chủ MySQL Thông tin về các bảng trong schema
Trong ví dụ này, bảng được sử dụng là bảng payment, các cột trong bảng là:
Kiểm tra các chỉ mục hiện đang có trên bảng với lệnh: show index from
payment;
Trang 19Từ bảng trên ta thấy các cột đã có chỉ mục là: payment_id (PRIMARY) và
staff_id, customer_id, retal_id (sencodary index) Tất cả các chỉ mục được lưu
trữ bằng cấu trúc B+-tree
Thực hiện một truy vấn đơn giản trên một cột chưa có chỉ mục, cụ thể ở đây là
cột payment_update với câu lệnh:
select * from sakila.payment where payment_date = '2005-08-17 00:51:32'
Ta thêm lệnh explain phía trước câu truy vấn để xem chi tiết các thông số về
cách MySQL thực hiện truy vấn: explain select * from sakila.payment where
payment_date = '2005-08-17 00:51:32'
Có thể thấy do cột payment_date chưa có chỉ mục nên việc htực hiện truy vấn
phải quét hết tất cả các record có trong bảng (type = ALL, rows = 16086)
Ta thêm chỉ mục cho cột payment_date bằng lệnh: create index
idx_payment_date on sakila.payment (payment_date);
Sau đó chạy lại truy vấn ở phía trên, kết quả thu được:
Sau khi thêm chỉ mục, truy vấn đã được tăng tốc đáng kể, số hàng phải quét
chỉ là một (type = ref, ref = const, rows = 1)
2 Cassandra
2.1 Lý thuyết về các dạng chỉ mục
Chỉ mục trong Cassandra sử dụng các thuộc tính khác với partition key (khóa
phân vùng) giúp truy vấn nhanh chóng, hiệu quả phù hợp với một điều kiện
nhất định
Các giá trị của cột được lập chỉ mục được chứa trong một bảng ẩn (SSTable),
riêng biệt với bảng chứa các giá trị đang được lập chỉ mục Cassandra có một
số kỹ thuật để đề phòng trường hợp không mong muốn trong đó dữ liệu có
thể được truy xuất không chính xác trong một truy vấn liên quan đến các chỉ
mục trên cơ sở các giá trị cũ trong chỉ mục
Trang 20Chỉ mục có thể được sử dụng cho collection, cột của collection và bất kỳ cột nào khác ngoại trừ counter column và static column
Trước khi đi vào tìm hiểu các loại chỉ mục, chúng ta cần hiểu rõ các khóa (key) trong Cassandra Primary key (khóa chính) có thể là một single key hoặc composite key Với trường hợp là single key, partition key chính là primary key Với trường hợp composite key, phần đầu tiên của primary key
là partition key (có thể single hoặc composite) và phần còn lại là clustering key
Primary key là khóa duy nhất (UNIQUE NOT NULL) xác định mỗi record
Partition key chịu trách nhiệm phân phối dữ liệu trên các nút, là cách tra cứu chính để tìm một tập hợp các hàng, tức là một phân vùng
Clustering key chịu trách nhiệm sắp xếp dữ liệu trong phân vùng (sắp xếp thứ tự)
Primary index:
Cassandra sử dụng partition key trong primary key như là một phương pháp truy cập chính trên cơ sở dữ liệu, partition key giúp xác định nút đang giữ dữ liệu, sau đó là tệp dữ liệu lưu trữ phân vùng dữ liệu Chỉ mục này được Cassandra tự động khởi tạo cho cột primary key sau khi bảng được tạo
Với các cột khác không phải là primary key thì ta không thể truy vấn trên các giá trị của cột đó, vì vậy ta cần phải tại secondary index cho các cột
đó để có thể thực hiện truy vấn được
Secondary index:
là chỉ mục được tạo cho các giá trị của cột không phải là primary key Secondary index rất khó sử dụng và có thể ảnh hưởng nhiều đến hiệu suất Vì Cassandra phân vùng dữ liệu trên nhiều nút, mỗi nút phải duy trì bản sao của chỉ mục dựa trên dữ liệu được lưu trữ trong các phân vùng mà nó sở hữu Secondary index được khuyên là không nên sử dụng trong các trường hợp sau:
Cột có quá nhiều giá trị duy nhất gây ảnh hưởng đến tốc độ đọc
Cột có quá ít giá trị duy nhất dẫn đến kết quả là một hàng quá lớn trong chỉ mục
Cột thường xuyên được cập nhật dữ liệu hoặc xóa: vì lượng lớn dữ liệu tombstone có thể không thể xử lý kịp
Hiện nay, qua mỗi phiên bản, Cassandra đã thêm và cải tiến các phiên bản secondary index của mình tốt hơn nhiều so với phiên bản secondary index đầu tiên (viết tắt là 2i) như: SASI, SAI, nhưng cách tốt nhất sẽ là lập mô hình
dữ liệu, thử nghiệm và so sánh benchmark
Trang 21SSTable Attached Secondary Index (SASI):
có thể được tạo trên một cột non-collection được xác định trong bảng SASI triển khai ba loại chỉ mục: PREFIX, CONTAINS, SPARSE SASI tốn ít tài nguyên hơn: sử dụng ít bộ nhớ, đĩa và CPU
Cho phép truy vấn với tiền tố và chứa trên chuỗi, tương tự như việc triển khai SQL của LIKE = 'foo%' hoặc LIKE = '% foo%' trong SELECT
Hỗ trợ lập chỉ mục SPARSE để cải thiện hiệu suất các truy vấn lớn, dày đặc như dữ liệu chuỗi thời gian
SASI tận dụng mô hình dữ liệu “write-once immutable ordered data-model” của cơ sở dữ liệu để xây dựng các chỉ mục khi dữ liệu được chuyển từ
memtable sang đĩa Cấu trúc dữ liệu chỉ mục SASI được xây dựng trong bộ nhớ khi SSTable được ghi và chuyển vào đĩa khi ghi tuần tự trước khi quá trình ghi SSTable hoàn tất Một tệp chỉ mục được ghi cho mỗi cột được lập chỉ mục
SASI được thực hiện bằng cách sử dụng cấu trúc B+-tree được ánh xạ bộ nhớ (memory mapped B+-tree) B+-tree cho phép các truy vấn phạm vi thực hiện nhanh chóng SASI tạo chỉ mục cho mỗi SSTable Một số tính năng chính phát sinh từ thiết kế này là:
SASI có thể tham chiếu các hiệu số trong tệp dữ liệu, bỏ qua bộ lọc Bloom
và các chỉ mục phân vùng để đi thẳng đến nơi dữ liệu được lưu trữ
Khi các SSTables được thu gọn, các chỉ mục mới được tạo tự động
Storage Attached Index (SAI):
là một secondary index mới của Cassandra SAI được xây dựng dựa trên nhiều kỹ thuật đã được sử dụng trong SASI SAI chia sẻ dữ liệu chỉ mục chung cho nhiều chỉ mục trên cùng một bảng Tính năng độc đáo này cung cấp cho người dùng khả năng tạo nhiều chỉ mục hơn mà không gặp phải các vấn đề về khả năng mở rộng
SAI được tối ưu hóa để lưu trữ Token và offset được lưu trữ một lần cho mỗi SSTable Chỉ mục cột truy cập tệp chứa token và offset bằng cách sử dụng row ID Các tập hợp giá trị được nén bằng cách sử dụng mã hóa Frame of Reference (FoR) trong khi token thì không vì token sử dụng đủ 8 byte và do
đó không thể nén được
Việc triển khai chỉ mục chỉ cần lưu trữ một row ID trong posting list Row ID được dịch sang decorated key thông qua tệp token/offset và SSTableReader
#keyAt