INDEX (chỉ mục) trong MySQL

INDEX (chỉ mục) trong MySQL
INDEX (chỉ mục) trong MySQL

Chức năng của INDEX (chỉ mục) trong MySQL

INDEX (chỉ mục) trong MySQL được sử dụng để INDEX (chỉ mục) cho 1 cột hoặc nhiều cột nhằm giúp cho khi bạn WHERE dữ liệu sẽ truy vấn nhanh hơn.

Kiểm tra truy vấn khi bảng chưa INDEX (chỉ mục) trong MySQL

EXPLAIN SELECT ip,thoigian FROM `tb_truycap` WHERE ip='162.120.184.46';
<?php
   $dbhost = 'localhost';
   $dbuser = 'webmoi_userdata'; // Tên username
   $dbpass = 'xgZwEfQWE'; // Mật khẩu
   // Kết nối đến tên username
   $conn = mysql_connect($dbhost, $dbuser, $dbpass);
   if(! $conn ){
     die('Không kết nối được: ' . mysql_error());
   }
   // Chọn tên database
   mysql_select_db('webmoi_tendata');
   // Xét kiểu tiếng việt 
   mysql_query('SET NAMES "utf8"');
  // Kiểm tra truy vấn khi bảng chưa INDEX (chỉ mục) trong MySQL
   echo "<b>Kiểm tra truy vấn khi bảng chưa INDEX (chỉ mục) trong MySQL</b><br>";
   $sql ="EXPLAIN SELECT ip,thoigian FROM `tb_truycap` WHERE ip='162.120.184.46'";	
   $ketquamot = mysql_query($sql,$conn);
   if(!$ketquamot){
	  die('Không thể Kiểm tra truy vấn: ' . mysql_error());  
   }
   $ktract = mysql_fetch_array($ketquamot, MYSQL_ASSOC);
   echo "rows (số dòng quét qua): ".$ktract['rows']."<br>";
   echo "possible_keys: ".$ktract['possible_keys']."<br>";
   echo "key: ".$ktract['key']."<br>";
   echo "key_len: ".$ktract['key_len']."<br>";
   // Đóng kết nối database
   mysql_close($conn);
?>

Kết quả:

Kiểm tra truy vấn khi bảng chưa INDEX (chỉ mục) trong MySQL
rows (số dòng quét qua): 4015
possible_keys:
key:
key_len:

Lúc chưa index cột thì lúc where 1 ip thì phải quét hết toàn bộ số dòng có trong bảng.

Các loại INDEX (chỉ mục) trong MySQL

INDEX (chỉ mục) cho 1 cột trong MySQL

Bạn kiểm tra code nếu có trường hợp WHERE chỉ 1 cột mà cột đó có thể INDEX (chỉ mục) được thì mới đêm ra dùng, chứ INDEX (chỉ mục) mà không dùng thì rất ảnh hưởng đến quá trình tải web, vì nhóm index cũng cập nhật lại mỗi khi cột thay đổi hoặc thêm mới, nhóm này index cho cột nào thì khi where cột đó sẽ quét ít dòng hơn (thậm chí chỉ quét 1 hàng nếu giá trị của cột đó không trùng lặp) nên truy vấn rất nhanh.

CREATE INDEX i_ip ON tb_truycap (ip);
<?php
   $dbhost = 'localhost';
   $dbuser = 'webmoi_userdata'; // Tên username
   $dbpass = 'xgZwEfQWE'; // Mật khẩu
   // Kết nối đến tên username
   $conn = mysql_connect($dbhost, $dbuser, $dbpass);
   if(! $conn ){
     die('Không kết nối được: ' . mysql_error());
   }
   // Chọn tên database
   mysql_select_db('webmoi_tendata');
   // Xét kiểu tiếng việt 
   mysql_query('SET NAMES "utf8"');
   //INDEX (chỉ mục) cho 1 cột trong MySQL
   echo "<b>INDEX (chỉ mục) cho 1 cột trong MySQL</b><br>";
   
   // INDEX (chỉ mục) cho 1 cột IP
   echo "<b>INDEX (chỉ mục) cho 1 cột IP</b><br>";
   $sql ="CREATE INDEX i_ip ON tb_truycap (ip)";	
   $ketquamot = mysql_query($sql,$conn);
   if(!$ketquamot){
	  die('Không thể INDEX (chỉ mục) cho 1 cột IP: ' . mysql_error());  
   }else{
	  echo "INDEX (chỉ mục) cho 1 cột IP thành công!"; 
   }
   // INDEX (chỉ mục) cho 1 cột thoigian
   echo "<b>INDEX (chỉ mục) cho 1 cột thoigian</b><br>";
   $sql ="CREATE INDEX i_thoigian ON tb_truycap (thoigian)";	
   $ketquahai = mysql_query($sql,$conn);
   echo "<br>";
   if(!$ketquahai){
	  die('Không thể INDEX (chỉ mục) cho 1 cột thoigian: ' . mysql_error());  
   }else{
	  echo "INDEX (chỉ mục) cho 1 cột thoigian thành công!"; 
   }
   // Đóng kết nối database
   mysql_close($conn);
?>

Kết quả:

INDEX (chỉ mục) cho 1 cột trong MySQL
INDEX (chỉ mục) cho 1 cột IP
INDEX (chỉ mục) cho 1 cột IP thành công!
INDEX (chỉ mục) cho 1 cột thoigian
INDEX (chỉ mục) cho 1 cột thoigian thành công!

INDEX (chỉ mục) cho nhiều cột trong MySQL

Bạn kiểm tra code của bạn nếu có trường hợp nào WHERE nhiều cột mà những cột đó có thể index được thì mới index những cột đó vô một nhóm.

CREATE INDEX i_thoigian_ip ON tb_truycap (thoigian,ip);
<?php
   $dbhost = 'localhost';
   $dbuser = 'webmoi_userdata'; // Tên username
   $dbpass = 'xgZwEfQWE'; // Mật khẩu
   // Kết nối đến tên username
   $conn = mysql_connect($dbhost, $dbuser, $dbpass);
   if(! $conn ){
     die('Không kết nối được: ' . mysql_error());
   }
   // Chọn tên database
   mysql_select_db('webmoi_tendata');
   // Xét kiểu tiếng việt 
   mysql_query('SET NAMES "utf8"');
   //INDEX (chỉ mục) cho nhiều cột trong MySQL
   echo "<b>INDEX (chỉ mục) cho nhiều cột trong MySQL</b><br>";
   $sql ="CREATE INDEX i_thoigian_ip ON tb_truycap (thoigian,ip)";	
   $ketquamot = mysql_query($sql,$conn);
   if(!$ketquamot){
	  die('Không thể INDEX (chỉ mục) cho i_thoigian_ip: ' . mysql_error());  
   }else{
	  echo "INDEX (chỉ mục) cho tên nhóm i_thoigian_ip thành công!"; 
   }
   // Đóng kết nối database
   mysql_close($conn);
?>

Kết quả:

INDEX (chỉ mục) cho nhiều cột trong MySQL
INDEX (chỉ mục) cho tên nhóm i_thoigian_ip thành công!

Kiểm tra truy vấn khi bảng đã INDEX (chỉ mục) trong MySQL

Kiểm tra truy vấn khi bảng đã INDEX (chỉ mục) 1 cột trong MySQL

EXPLAIN SELECT ip,thoigian FROM `tb_truycap` WHERE ip='157.55.39.59';
<?php
   $dbhost = 'localhost';
   $dbuser = 'webmoi_userdata'; // Tên username
   $dbpass = 'xgZwEfQWE'; // Mật khẩu
   // Kết nối đến tên username
   $conn = mysql_connect($dbhost, $dbuser, $dbpass);
   if(! $conn ){
     die('Không kết nối được: ' . mysql_error());
   }
   // Chọn tên database
   mysql_select_db('webmoi_tendata');
   // Xét kiểu tiếng việt 
   mysql_query('SET NAMES "utf8"');
   // Kiểm tra truy vấn khi bảng đã INDEX (chỉ mục) cột IP trong MySQL
   echo "<b>Kiểm tra truy vấn khi bảng đã INDEX (chỉ mục) cột IP trong MySQL</b><br>";
   $sql ="EXPLAIN SELECT ip,thoigian FROM `tb_truycap` WHERE ip='157.55.39.59'";	
   $ketquamot = mysql_query($sql,$conn);
   if(!$ketquamot){
	  die('Không thể Kiểm tra truy vấn: ' . mysql_error());  
   }
   $ktract = mysql_fetch_array($ketquamot, MYSQL_ASSOC);
   echo "rows (số dòng quét qua): ".$ktract['rows']."<br>";
   echo "possible_keys: ".$ktract['possible_keys']."<br>";
   echo "key: ".$ktract['key']."<br>";
   echo "key_len: ".$ktract['key_len']."<br>";
   // Kiểm tra truy vấn khi bảng đã INDEX (chỉ mục) cột IP trong MySQL
   echo "<b>Kiểm tra truy vấn khi bảng đã INDEX (chỉ mục) cột thoigian trong MySQL</b><br>";
   $sql ="EXPLAIN SELECT ip,thoigian FROM `tb_truycap` WHERE thoigian='1754538388'";	
   $ketquahai = mysql_query($sql,$conn);
   if(!$ketquahai){
	  die('Không thể Kiểm tra truy vấn: ' . mysql_error());  
   }
   $ktract = mysql_fetch_array($ketquahai, MYSQL_ASSOC);
   echo "rows (số dòng quét qua): ".$ktract['rows']."<br>";
   echo "possible_keys: ".$ktract['possible_keys']."<br>";
   echo "key: ".$ktract['key']."<br>";
   echo "key_len: ".$ktract['key_len']."<br>";
   // Đóng kết nối database
   mysql_close($conn);
?>

Kết quả:

Kiểm tra truy vấn khi bảng đã INDEX (chỉ mục) cột IP trong MySQL
rows (số dòng quét qua): 1
possible_keys: i_ip
key: i_ip
key_len: 62
Kiểm tra truy vấn khi bảng đã INDEX (chỉ mục) cột thoigian trong MySQL
rows (số dòng quét qua): 1
possible_keys: i_thoigian,i_thoigian_ip
key: i_thoigian_ip
key_len: 4

Kiểm tra truy vấn khi bảng đã INDEX (chỉ mục) nhiều cột trong MySQL

EXPLAIN SELECT ip,thoigian FROM `tb_truycap` WHERE ip='157.55.39.59' and thoigian='1754694083';
<?php
   $dbhost = 'localhost';
   $dbuser = 'webmoi_userdata'; // Tên username
   $dbpass = 'xgZwEfQWE'; // Mật khẩu
   // Kết nối đến tên username
   $conn = mysql_connect($dbhost, $dbuser, $dbpass);
   if(! $conn ){
     die('Không kết nối được: ' . mysql_error());
   }
   // Chọn tên database
   mysql_select_db('webmoi_tendata');
   // Xét kiểu tiếng việt 
   mysql_query('SET NAMES "utf8"');
   // Kiểm tra truy vấn khi bảng đã INDEX (chỉ mục) nhiều cột trong MySQL
   echo "<b>Kiểm tra truy vấn khi bảng đã INDEX (chỉ mục) nhiều cột trong MySQL</b><br>";
   $sql ="EXPLAIN SELECT ip,thoigian FROM `tb_truycap` WHERE ip='157.55.39.59' and thoigian='1754694083'";	
   $ketquamot = mysql_query($sql,$conn);
   if(!$ketquamot){
	  die('Không thể Kiểm tra truy vấn: ' . mysql_error());  
   }
   $ktract = mysql_fetch_array($ketquamot, MYSQL_ASSOC);
   echo "rows (số dòng quét qua): ".$ktract['rows']."<br>";
   echo "possible_keys: ".$ktract['possible_keys']."<br>";
   echo "key: ".$ktract['key']."<br>";
   echo "key_len: ".$ktract['key_len']."<br>";
   // Đóng kết nối database
   mysql_close($conn);
?>

Kết quả:

Kiểm tra truy vấn khi bảng đã INDEX (chỉ mục) nhiều cột trong MySQL
rows (số dòng quét qua): 1
possible_keys: i_ip,i_thoigian,i_thoigian_ip
key: i_thoigian_ip
key_len: 66

Những lưu ý khi sử dụng INDEX (chỉ mục) trong MySQL

- Cột dùng làm index không cho phép NULL.

- Giá trị trên cột dùng làm index không nên bị trùng lặp.

- Bạn nên kiểm tra code nếu cột nào cần dùng WHERE mà có thể index được thì hãy dùng.

- Không nên index nhiều vì mỗi lần cập nhật cột thì bên index vẫn phải làm việc để cập nhật lại.

- Nhóm index 1 cột thì thường dùng cho WHERE 1 cột.

- Nhóm index nhiều cột thì thường dùng cho WHERE nhiều cột kết hợp.

- Giá trị của cột index không nên UPDATE thường xuyên vì như vậy nhóm index sẽ làm việc liên tục.

Cách quản lý INDEX (chỉ mục) trong MySQL

Sau khi tạo INDEX, việc quản lý định kỳ giúp cấu trúc bảng luôn phù hợp với cách ứng dụng truy vấn dữ liệu. Một chỉ mục có thể hữu ích ở thời điểm này nhưng trở nên dư thừa khi câu lệnh SQL hoặc cấu trúc bảng thay đổi.

Quản lý INDEX thường tập trung vào ba việc chính: kiểm tra các chỉ mục hiện có, loại bỏ chỉ mục không cần thiết và điều chỉnh lại chỉ mục khi nhu cầu truy vấn thay đổi.

Kiểm tra danh sách INDEX đang có trong MySQL

Trước khi tạo thêm INDEX, nên kiểm tra bảng đã có những chỉ mục nào. Cách này giúp tránh tạo nhiều INDEX có chức năng gần giống nhau, đồng thời dễ phát hiện các cột đang được lập chỉ mục chưa hợp lý.

SHOW INDEX FROM users;

Kết quả cho biết tên INDEX, các cột tham gia, thứ tự cột và một số thông tin liên quan. Khi phân tích hiệu suất truy vấn, nên xem INDEX cùng với cấu trúc câu lệnh SQL thay vì đánh giá chỉ dựa trên số lượng chỉ mục.

Xóa INDEX (chỉ mục) không còn cần thiết

INDEX không được sử dụng thường xuyên có thể làm tăng dung lượng lưu trữ và khiến MySQL phải cập nhật thêm dữ liệu chỉ mục khi thực hiện INSERT, UPDATE hoặc DELETE. Vì vậy, những INDEX dư thừa nên được xem xét loại bỏ.

DROP INDEX idx_email ON users;

Trước khi xóa, cần xác định INDEX đó không còn phục vụ các truy vấn quan trọng. Đặc biệt với bảng lớn, không nên xóa chỉ mục chỉ vì một câu truy vấn cụ thể không sử dụng nó.

Thay đổi INDEX để phù hợp với truy vấn

Khi cách ứng dụng truy xuất dữ liệu thay đổi, INDEX cũ có thể không còn phù hợp. Trong trường hợp này, có thể xây dựng lại INDEX với các cột và thứ tự ưu tiên phù hợp hơn với điều kiện lọc, sắp xếp hoặc kết hợp dữ liệu.

Ví dụ, nếu truy vấn thường xuyên lọc theo status rồi tiếp tục theo created_at, một INDEX kết hợp có thể phù hợp hơn so với các INDEX đơn lẻ được tạo riêng trên từng cột.

CREATE INDEX idx_status_created
ON orders (status, created_at);

Khi thay đổi INDEX, nên kiểm tra lại truy vấn bằng EXPLAIN để xem MySQL có lựa chọn chỉ mục mới hay không. Mục tiêu không phải tạo càng nhiều INDEX càng tốt mà là xây dựng hệ thống chỉ mục phù hợp với những truy vấn thực tế của ứng dụng.

Lời kết

Cảm ơn các bạn đã tham khảo bài viết INDEX (chỉ mục) trong MySQL.

Tải file database .sql về nếu muốn kiểm tra hoặc thực hành Tải về.

  • 0 Bình luận
Trần Thị Vân | Content Creator Web Mới
Trần Thị Vân
Trần Thị Vân là Content Creator tại Web Mới, phụ trách nghiên cứu, biên soạn nội dung và chia sẻ kiến thức về website, SEO, lập trình cùng các xu hướng công nghệ
Đánh giá
Chia sẻ nội dung đánh giá của bạn về INDEX (chỉ mục) trong MySQL
Email, Điện thoại của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *
Đánh giá của bạn
Tên *
Email
Số điện thoại *
Bình luận, Hỏi đáp
Yêu Cầu Báo Giá
Gửi trang web mẫu cần làm theo, chúng tôi sẽ báo giá đến bạn từ Email (tanlucit09@gmail.com - Bùi Tấn Lực) hoặc Zalo (Lực IT - 0398259259) !