2. Nội dung
1. Cơ bản về SQL & Tối ưu kiểu
2. Tối ưu sử dụng index
3. Tối ưu câu lệnh query
4. Tối ưu thiết kế bảng
5. Các kỹ thuật mới nâng cao hiệu năng
2
3. Index là gì?
• Index còn được gọi là key trong MySQL
• Một dạng data structure được
• Index là 1 tiêu chí để đánh giá good
performance
• Index có thể tăng hiệu năng lên 10 lần
3
4. Index là gì?
4
CREATE TABLE userinfo (
id int unsigned NOT NULL AUTO_INCREMENT,
name varchar(64) NOT NULL DEFAULT '',
email varchar(64) NOT NULL DEFAULT '',
password varchar(64) NOT NULL DEFAULT '',
dob date DEFAULT NULL,
address varchar(255) NOT NULL DEFAULT '',
city varchar(64) NOT NULL DEFAULT '',
state_id tinyint unsigned NOT NULL DEFAULT '0',
zip varchar(8) NOT NULL DEFAULT '',
country_id smallint unsigned NOT NULL DEFAULT '0',
gender ('M','F')NOT NULL DEFAULT 'M',
account_type varchar(32) NOT NULL DEFAULT '',
verified tinyint NOT NULL DEFAULT '0',
allow_mail tinyint unsigned NOT NULL DEFAULT '0',
parrent_account int unsigned NOT NULL DEFAULT '0',
closest_airport varchar(3) NOT NULL DEFAULT '',
PRIMARY KEY (id),
UNIQUE KEY email (email),
KEY country_id (country_id),
KEY state_id (state_id),
KEY state_id_2 (state_id,city,address)
) ENGINE=InnoDB
5. Tối ưu sử dụng index
• Các loại index
• Chiến lược sử dụng index
• Tổng hợp
5
6. Ví dụ
• Index sử dụng B-Tree
6
CREATE TABLE People (
last_name varchar(50) not null,
first_name varchar(50) not null,
dob date not null,
gender enum('m', 'f')not null,
key(last_name, first_name, dob)
);
7. B-Tree index
• Match the full value: Tìm kiếm khớp sử dụng full value của index.
• Match a leftmost prefix: Tìm kiếm người có last name là Allen
• Match a column prefix: Tìm kiếm người có last name bắt đầu từ chữ
J
• Match a range of values: Tìm kiếm những người có last name từ
Allen -> Barymore
• Match one part exactly and match a range on another part: Tìm
người có last name Allen, và first name bắt đầu bằng K
• Index-only queries: Là những query chỉ access vào index, không
phải row
=> Viết câu truy vấn ứng với các trường hợp
7
8. B-Tree index
• Không hữu dụng khi tìm kiếm từ phía bên phải
– Tìm theo first name và dob mà bỏ qua last_name
• Không thể bỏ qua những column cùng index mà
không phải bên trái
– Tìm theo last name và dob bỏ qua fist name
• Store engine không tối ưu cho access khi tìm
kiếm theo range ở bên phải
– WHERE last_name="Smith" AND first_name LIKE 'J%' AND
dob='1976-12-23'
=> Thứ tự column trong index rất quan trọng
8
9. Hash index
• Index HASH(fname)
• Store engine MEMORY
9
CREATE TABLE testhash (
fname VARCHAR(50) NOT NULL,
lname VARCHAR(50) NOT NULL,
KEY USING HASH(fname)
) ENGINE=MEMORY;
10. Hash index
• Không dùng cho sắp xếp
• Phải tuy vấn toàn bộ cột trong index
• Không thể tìm kiếm range
– Hỗ trợ =, <>, IN
• Tìm rất nhanh
• InnoDB với những row được access nhiều
lần sẽ tự động build hash index cho row
đó lên truocs B-Tree
10
11. Hash index
• Với những store engine không hỗ trợ thì
làm như nào?
– SELECT id FROM url WHERE
url="http://www.mysql.com/";
11
12. Hash index
12
SELECT id FROM url WHERE
url="http://www.mysql.com"
AND url_crc=CRC32("http://www.mysql.com");
CREATE TRIGGER pseudohash_crc_ins
BEFORE INSERT ON pseudohash FOR EACH ROW
BEGIN SET NEW.url_crc=crc32(NEW.url);
END; //
CREATE TRIGGER pseudohash_crc_upd
BEFORE UPDATE ON pseudohash FOR EACH ROW
BEGIN SET NEW.url_crc=crc32(NEW.url);
END; //
13. Chiến lược sử dụng index
• Cô lập cột trong query
• Sử dụng nhiều index
• Sử dụng trong query lồng nhau
• Sử dụng cho Sort
13
14. Cô lập cột trong query
• Câu query sau không thể sử dụng được index
• Không được thực hiện phép toán với index
14
SELECT actor_id
FROM sakila.actor
WHERE actor_id + 1 = 5;
15. Cô lập cột trong query
15
TO_DAYS(CURRENT_DATE) - TO_DAYS(date_col) <= 10;
char_length(string_col) > 0;
col1 > col2 – 1; # col2 có trong index
Col1 + col2 = 10; # col1 + col2 có trong index
16. Sử dụng nhiều index
• Có nên đánh index cho những col xuất
hiện trong WHERE không?
16
CREATE TABLE t (
c1 INT,
c2 INT,
c3 INT,
KEY(c1),
KEY(c2),
KEY(c3)
);
17. Sử dụng nhiều index
• Có nên đánh index cho những col xuất
hiện trong WHERE không?
17
SELECT film_id, actor_id FROM film_actor
WHERE actor_id = 1 OR film_id = 1;
# KEY(actor_id) KEY(film_id)
18. Sử dụng nhiều index
• Sử dụng index gồm nhiều col trong điều kiện
AND không phải nhiều index
• Với điều kiện OR sẽ tốn rất nhiều CPU và
memory resource
• Trường hợp muốn đã đánh index có thể sử
dụng IGNORE INDEX để bỏ qua index
18
19. Sử dụng nhiều index
• Những key nào chắc chắn không cần thiết
19
CREATE TABLE userinfo (
…
PRIMARY KEY (id),
UNIQUE KEY email (email),
KEY email (email)
KEY country_id (country_id),
KEY state_id (state_id),
KEY state_id_2 (state_id, city),
KEY state_id_3 (state_id,city,address),
KEY state_id_4 (address,city,state_id),
) ENGINE=InnoDB
20. Sử dụng trong query lồng nhau
• Viết lại câu query sau trong trường hợp nhiều
bản ghi và kết quả trả về ít
20
mysql> EXPLAIN SELECT * FROM products WHERE actor='SEAN CARREY‘
-> AND title like '%APOLLO%'G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: products
type: ref
possible_keys: ACTOR,IX_PROD_ACTOR
key: ACTOR
key_len: 52
ref: const
rows: 10
Extra: Using where
21. Sử dụng trong query lồng nhau
21
mysql> EXPLAIN SELECT *
-> FROM products
-> JOIN (
-> SELECT prod_id
-> FROM products
-> WHERE actor='SEAN CARREY' AND title LIKE '%APOLLO%‘
-> ) AS t1 ON (t1.prod_id=products.prod_id)G
22. Sử dụng trong query lồng nhau
• Tối ưu câu truy vấn sau
22
SELECT <cols> FROM profiles
WHERE sex='M‘
ORDER BY rating LIMIT 100000, 10;
23. Sử dụng trong query lồng nhau
23
SELECT <cols> FROM profiles INNER JOIN (
SELECT <primary key cols> FROM profiles
WHERE x.sex='M' ORDER BY rating LIMIT 100000, 10
) AS x USING(<primary key cols>);
24. Sử dụng trong query lồng nhau
• Kết quả test
• query/sec càng cao thì chạy càng nhanh
24
Số bản ghi test Query gốc Query đã viết lại
30,000 products có actor là Sean Carrey, và
20,000 title có chứa Apollo
5 query/sec 5 query/sec
30,000 products có actor là Sean Carrey, và
40 title có chứa Apollo
7 query/sec 35 query/sec
50 products có actor là Sean Carrey, và 10
title có chứa Apollo
2400 query/sec 2000 query/sec
25. Sử dụng cho Sort
• col1 → col4 phải đúng thứ tự index
– KEY(col1, col2, col3, col4)
• Điều kiện trong phải là điều kiện ‘=‘
• Thứ tự sắp sếp phải cùng ASC hoặc DESC
25
WHERE col1 = ?, col2 = ? ORDER BY col3, col4
26. Sử dụng cho Sort
• Ví dụ
26
CREATE TABLE rental (
...
PRIMARY KEY (id),
UNIQUE KEY rental_date (rental_date,inventory_id,customer_id),
...
);
mysql> EXPLAIN SELECT rental_id, staff_id FROM sakila.rental
-> WHERE rental_date = '2005-05-25‘
-> ORDER BY inventory_id, customer_idG
*************************** 1. row ***************************
type: ref possible_keys: rental_date
key: rental_date
rows: 1
Extra: Using where
27. Sử dụng cho Sort
1. WHERE rental_date = '2005-05-25'ORDER BY
inventory_id DESC;
2. WHERE rental_date > '2005-05-25' ORDER BY
rental_date, inventory_id;
3. WHERE rental_date = '2005-05-25' ORDER BY
inventory_id DESC, customer_id ASC;
4. WHERE rental_date = '2005-05-25' ORDER BY
inventory_id, staff_id;
27
28. Sử dụng cho Sort
5. WHERE rental_date = '2005-05-25' ORDER BY
customer_id;
6. WHERE rental_date > '2005-05-25' ORDER BY
inventory_id, customer_id;
7. WHERE rental_date = '2005-05-25' AND inventory_id
IN(1,2) ORDER BY customer_ id;
28
29. Tổng hợp
• Ưu điểm
– Đẩy nhanh xử lý lọc, tìm kiếm
• Nhược điểm
– UPDATE, DELETE, INSERT đều dẫn đến
thay đổi toàn bộ index
29
30. Tổng hợp
• Đặc điểm của cột tạo nên index
– Bản ghi cần tìm kiếm ít, lượng data nhiều
– Hay được sử dụng với ORDER BY, điều kiện
– Thường NOT NULL
• Đặc điểm của cột không nên tạo Index
– Bản ghi cần tìm kiếm ít, table có kích thước bé
– Không có logic điều kiện
– Giá trị cột hay làm trong INSERT, UPDATE, DELETE
– Sử dụng trong biểu thức +,-,*,/,SUM, COUNT trong
WHERE
30
31. Tổng hợp
• Khi nào nên sử dụng index
– Khi so sánh bằng với giá trị cụ thể
– Khi JOIN a.name = b.name
– Khi cần giới hạn với =, >, >=, <, <=
– Khi cố định giá trị đầu tiên theo LIKE
– ORDER BY, GROUP BY theo prefix của chuỗi
31
32. Tổng hợp
• Khi nào không nên sử dụng index
– Khi bắt đầu LIKE bằng wild card
– Thông thường index sẽ không sử dụng
ORDER BY
– Khi field ORDER BY và WHERE khác nhau
nhưng chỉ đánh index trên một filed
– Trong trường hợp data dưới 1000 record,
mặc dù đánh index nhưng có thể không được
sử dụng
32