二級MySQL數據庫程序設計(六)

本博客爲《全國計算機等級考試二級MySQL數據庫程序設計教程》讀書筆記,請勿轉載用於其他商業用途。

課程目錄
第1章 數據庫的基本概念與設計方法
第2章 MySQL簡介
第3章 數據庫和表
第4章 表數據的基本操作
第5章 數據庫的查詢
第6章 索引
第7章 視圖
第8章 數據完整性約束與表維護語句
第9章 觸發器
第10章 事件
第11章 存儲過程與存儲函數
第12章 訪問控制與安全管理
第13章 備份與恢復
第14章 PHP和MySQL數據庫編程
第15章 開發實例

本章學習流程圖

在這裏插入圖片描述

本章學習大綱

索引是MySQL中一種十分重要的數據庫對象。它是數據庫性能調優技術的基礎,常用於實現數據的快速檢索。本章主要介紹索引的基本知識,以及在MySQL中通過使用SQL語句創建、查看和刪除索引的方法。

6.1 索引簡介

索引:就是根據表中的一列或者若干列按照一定順序建立的列值與記錄行之間的對應關係表,索引實質上是一張描述索引列的列值與原表中記錄行之間一一對應關係的有序表。

在MySQL中,通常用以下兩種方式訪問數據庫表的行數據:

(1)順序訪問
順序方式就是在表中實行全表掃描,從頭到尾逐行遍歷,知道在無序的行數據中找到符合條件的目標數據。這種方式實現比較簡單,但是當表中有大量數據的時候,效率非常低下。例如,在幾千萬條的數據中心查找少量的數據時,使用順序訪問方式將會遍歷所有的數據,花費大量的時間。顯然會影響到數據庫的處理能力。

(2)索引訪問
索引訪問,即通過遍歷索引來直接訪問表中記錄行的方式。使用這種方式的前提是對錶建立一個索引。在列上創建了索引之後,查找數據時可以直接根據該列上的索引找到對應記錄行的位置,從而快捷地查找到數據。索引存儲了指定列數據值的指針,根據指定的排序順序對這些指針排序。

注意:訪問數據庫表的兩種方式,順序訪問和索引訪問的區別。

例如,在學生信息表students中,如果基於student_id建立了索引,系統則建立了一張索引列到實際記錄的映射表,當用戶需要查找student_id爲“12022”的數據的時候,系統先在student_id索引上找到該記錄,然後通過映射表直接找到數據行,並且返回該行數據。因爲掃描索引的素的一般遠遠大於掃描實際數據行的速度,因此採用索引的方式可以大大提高數據庫的工作效率。

6.2 索引的存儲於分類

索引的類型和存儲引擎有關,每種存儲引擎所支持的索引類不一定完全相同。根據存儲方式的不同,MySQL中常用的索引在物理上分爲以下兩類:

(1)B-樹索引
B-樹索引又稱爲BTREE索引,目前,大部分的索引都是採用B-樹索引方式來存儲的。B-樹索引是一個典型的樹結構,其包含的組件主要是以下幾個:

  • 葉子結點
  • 分支節點
  • 根節點

B-樹索引可以進行全鍵值、鍵值範圍和鍵值前綴查詢,也可以對查詢結果進行ORDER BY排序。但BTREE索引必須遵循左邊前綴原則,要考慮以下幾點約束。

  • 查詢必須從索引的最左邊開始
  • 查詢不能跳過某一索引列,必須按照從左到右的順序進行匹配
  • 存儲引擎不能使用索引中範圍條件右邊的列

(2)哈希索引

哈希:Hash,一般翻譯爲“散列”,也有直接音譯“哈希”的,就是把任意長度的輸入(又叫做預映射,pre-image),通過散列算法,變成固定長度的輸出,該輸出就是散列值。

哈希索引(HASH)也稱爲散列索引或HASH索引。MySQL目前僅有MEMORY存儲引擎和HEAP存儲引擎支持這類索引。其中MEMORY存儲引擎可以支持B-樹索引和HASH索引,且將HASH索引當成默認索引。HASH索引不是基於樹形的數據結構查找數據,而是根據索引對應列的哈希值的方法獲取表的記錄行。哈希索引的最大特點是訪問速度快,但是也存在一些缺點:

  • MySQL需要讀取表中索引列的值來參與散列計算,散列計算是一個比較耗時的操作。也就是說,相對B-樹索引來說,建立哈希索引會耗費更多的時間。
  • 不能使用HASH索引排序。
  • HASH索引只支持等值比較,如“=”、“IN()”、“<=>”。
  • HASH索引不支持鍵的部分匹配,因爲在計算HASH值的時候是通過整個索引值來計算的。

根據索引的具體用途,MySQL中的索引在邏輯上分爲以下五類:

(1)普通索引
最基本的索引類型,唯一任務是加快對數據的訪問速度,沒有任何限制。創建普通索引時,通常使用的關鍵字是INDEX或KEY。

(2)唯一性索引
不允許索引列具有相同索引值的索引。如果能確定某個數據列只包含彼此各不相同的值,在爲這個數據創建索引的時候就應該用關鍵字UNIQUE把它定義爲一個唯一索引。創建唯一索引的目的往往不是爲了提高訪問速度,而是爲了避免數據出現重複。

(3)主鍵
是一種唯一性索引。即不允許重複或者值爲空,並且每個表只能有一個主鍵。主鍵可以在創建表的時候指定,也可以通過修改表的方式添加。必須指定關鍵字PRIMARY KEY

(4)空間索引
主要用於地理空間數據類型GEOMETRY。

(5)全文索引
只能在VARCHAR或TEXT類型的列上創建,並且只能在MyISAM表中創建。

索引在邏輯上分爲以上5類,但在實際使用中,通常被創建爲單列索引和組合索引:

(1)單列索引
索引只包含原表的一個列。

(2)組合索引
也稱爲符合索引或多列索引,相對於單列索引來說,組合索引是將原表的多個列共同組成一個索引。

注意,一個表可以有多個單列索引,但這些索引不是組合索引。一個組合索引實質上爲表的查詢提供了多個索引,以此來加快查詢進度。

6.3 創建索引

MySQL提供了3種創建索引的方法:

❶ 使用CREATE INDEX語句
可以使用專門用於創建索引的CREATE INDEX語句在一個已有的表上創建索引,但該語句不能創建主鍵。

語法格式:

CREATE <索引名> ON <表名> (<列名> [<長度>][ASC|DESC])

語法說明:

  • <索引名>:指定索引名。一個表可以創建多個索引,但每個索引在該表中的名稱時唯一的。
  • <表名>:指定要創建索引的表名。
  • <列名>:指定要創建索引的列名。通常可以考慮將查詢語句中在JOIN子句和WHERE子句裏經常出現的列作爲索引。
    ①<列名>:指定要創建索引的列名。通常可以考慮將查詢語句中的JOIN子句和WHERE子句裏經常出現的列作爲索引。
    ②<長度>:可選項。指定使用列前的length個字符來創建索引。使用列的一部分創建索引有利於減小索引文件的大小。在某些情況下,只能對列的前綴進行索引。
    ③ASC|DESC:可選項。

【例6-1】查詢數據庫 my_test 中表 students 中,根據學生姓名前三個字符,採用默認的索引類型,創建一個升序索引 index_student。

mysql> create index index_student
    -> on students(student_name(3) asc);
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id:    33
Current database: my_test

Query OK, 0 rows affected (2.44 sec)
Records: 0  Duplicates: 0  Warnings: 0

語句執行成功後,採用SHOW INDEX命令顯示已經創建的索引。

mysql> show index from students;
+----------+------------+---------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table    | Non_unique | Key_name      | Seq_in_index | Column_name  | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+----------+------------+---------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| students |          0 | PRIMARY       |            1 | student_id   | A         |          11 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
| students |          1 | index_student |            1 | student_name | A         |          13 |        3 |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
+----------+------------+---------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
2 rows in set (0.28 sec)

執行完後,可以看到已經建立了基於student_name的索引 index_student。(在Key_name列)

【例6-2】查詢數據庫 my_test 中表 students 中,根據 student_name 和 student_id 採用 BTREE 的索引類型,創建一個複合索引 index_stud。

mysql> create index index_stud
    -> on students(student_name,student_id)
    -> using btree;
Query OK, 0 rows affected (1.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show index from students;
+----------+------------+---------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table    | Non_unique | Key_name      | Seq_in_index | Column_name  | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+----------+------------+---------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| students |          0 | PRIMARY       |            1 | student_id   | A         |          11 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
| students |          1 | index_student |            1 | student_name | A         |          13 |        3 |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
| students |          1 | index_stud    |            1 | student_name | A         |          13 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
| students |          1 | index_stud    |            2 | student_id   | A         |          13 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
+----------+------------+---------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
4 rows in set (0.27 sec)

❷ 使用CREATE TABLE語句
索引頁可以在創建表的同時創建。在CREATE TABLE語句語法添加以下語句:

  • 語法格式:
CONSTRAINT PRIMARY KEY [索引類型] (<列名>,...)

CREATE TABLE語句中添加詞句,表示在創建新表的同時創建該表的主鍵

  • 語法格式:
KEY | INDEX [索引名] [索引類型] (<列名>,...)

CREATE TABLE語句中添加詞句,表示在創建新表的同時創建該表的索引

  • 語法格式:
UNIQUE [INDEX | KEY]
[<索引名>][<索引類型>](<列名>,...)

CREATE TABLE語句中添加詞句,表示在創建新表的同時創建該表的唯一性索引

  • 語法格式:
FOREIGN KEY <索引名> <列名>

CREATE TABLE語句中添加詞句,表示在創建新表的同時創建該表的外鍵

【例6-3】在已有的數據庫 my_test 上新建一個課程信息表包含下列字段:課程號、課程名稱、上課教室和任課老師姓名。要求在創建該表的同時,將課程號作爲主鍵,並且給課程名稱創建索引。

mysql> use my_test;
Database changed
mysql> create table course
    -> (
    -> course_id int not null,
    -> course_name char(50) not null,
    -> course_place char(50) not null,
    -> course_teacher char(50) not null,
    -> primary key(course_id),              /*主鍵*/
    -> index index_course(course_name)      /*課程名創建索引*/
    -> );
Query OK, 0 rows affected (1.33 sec)

注意:MySQL可以在一個表上同時創建多索引,使用PIRMARY KEY的列必須是一個具有NOT NULL屬性的列。

❸ 使用ALTER TABLE語句
CREATE INDEX語句可以在一個已有的表上創建索引,ALTER TABLE語句也可以在一個已有表上創建索引。在使用ALTER TABLE修改表的同時,可以向已有的表添加索引,具體做法是在ALTER TABLE語句中添加以下語法成分的某一項或幾項。

  • 語法格式:
ADD INDEX [<索引名>] [<索引類型>] (<列名>,...)

ALTER TABLE語句中添加此語法成分,表示在修改表的同時爲該表添加索引

  • 語法格式:
ADD PRIMARY KEY [索引類型] (<列名>,...)

ALTER TABLE語句中添加此語法成分,表示在修改表的同時爲該表添加主鍵

  • 語法格式:
ADD UNIQUE [INDEX | KEY] [<索引名>][<索引類型>](<列名>,...)

ALTER TABLE語句中添加此語法成分,表示在修改表的同時爲該表添加唯一性索引

  • 語法格式:
ADD FOREIGN KEY <索引名> <列名>

ALTER TABLE語句中添加此語法成分,表示在修改表的同時爲該表添加外鍵

【例6-4】在已有的數據庫 my_test 表 course 中,爲courese_place字段添加一個非唯一的索引,取名爲 index_place。

mysql> alter table course
    -> add index index_place(course_place);
Query OK, 0 rows affected (1.17 sec)
Records: 0  Duplicates: 0  Warnings: 0

6.4 查看索引

在MySQL中,如果要查看已經創建的索引情況,可以使用SHOW INDEX語句查看錶中創建的索引。

語法格式:

SHOW INDEX FROM <表名> [FROM <數據庫名>]

語法說明:

  • <表名>:要顯示索引的表。
  • <數據庫名>:要顯示的表所在的數據庫。

【例6-5】顯示數據庫 my_test 中的表 course 的索引情況。

mysql> show index from course from my_test;
+--------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table  | Non_unique | Key_name     | Seq_in_index | Column_name  | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+--------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| course |          0 | PRIMARY      |            1 | course_id    | A         |           0 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
| course |          1 | index_course |            1 | course_name  | A         |           0 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
| course |          1 | index_place  |            1 | course_place | A         |           0 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
+--------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
3 rows in set (0.35 sec)

該語句會返回一張表,包含Table等幾個字段,說明如下:

  • Table:表的名稱
  • Non_unique:用於顯示,該索引是否不是唯一索引。如果不是唯一索引,則該列的顯示值爲1;如果是唯一索引,該列的顯示值爲0。
  • Key_name:索引的名稱。
  • Seq_in_index:索引中的序列號,從1開始技術。
  • Column_name:列名稱。
  • Collation:顯示列以何種順序存儲在索引中。在MySQL中,升序顯示值’A’(升序),如果顯示爲NULL則表示無分類。
  • Cardinality:顯示索引中唯一值數目的估計值。基數根據被存儲爲整數的統計數據計數,所以即時對於小型表,該值也沒有必要是精確的。基數越大,當進行聯合時,MySQL使用該索引的機會就越大。
  • Sub_part:如果列只是被部分地編入索引,則爲被編入索引的字符的數目。如果整列被編入索引,則爲NULL。
  • Packed:指示關鍵字如何被壓縮。如果沒有被壓縮,則爲NULL。
  • Index_type:顯示索引使用的類型和方法(BTREE, FULLTEXT, HASH, RTREE)。
  • Comment:顯示評註。

6.5 刪除索引

當一個索引不在需要時,可以使用DROP INDEX語句或者ALTER TABLE語句來對索引進行刪除。

❶ 使用DROP INDEX語句

語法格式:

DROP INDEX <索引名> ON <表名>

語法說明:

  • <索引名>:要刪除的索引名。
  • <表名>:指定該索引所在的表名。

【例6-6】刪除例6-4中創建的索引 index_place。

mysql> drop index index_place on course;
Query OK, 0 rows affected (0.43 sec)
Records: 0  Duplicates: 0  Warnings: 0

❷ 使用ALTER TABLE語句
根據ALTER TABLE語句的語法可知,該語句也可以用於刪除索引。具體使用方法是將ALTER TABLE語句的語法中部分指定爲以下子句中的某一項。

  • DROP PRIMARY KEY:表示刪除表中的主鍵。一個表只有一個主鍵,主鍵也是一個索引。
  • DROP INDEX index_name:表示刪除名爲index_name的索引。
  • DROP FOREIGN KEY fk_symbol:表示刪除外鍵。

【例6-6】刪除數據庫 my_test 的表 students 的索引 index_students。

mysql> alter table students
    -> drop index index_students;

注意:如果刪除的列是索引的組成部分,那麼在刪除該列時,也會將該列從索引中刪除;如果組成索引的所有列都被刪除,則整個索引將被刪除。

6.6 索引進階

索引雖然可以加快查詢速度,提高MySQL的處理性能,但是過多的使用索引也會造成下面的一些弊端。

  • 創建索引和維護索引要耗費時間,這種時間隨着數據量的增加而增加。
  • 除了數據表佔數據空間之外,每一個索引還要佔一定的物理空間。如果要建立聚簇索引,那麼需要的空間就會更大。
  • 當對錶中的數據進行增加、刪除和修改的時候,索引也要動態地維護,這樣就降低了數據的維護速度。

索引只是提高效率的一個因素,因此在建立索引的時候應該遵循以下原則:

  • 在經常需要搜索的列上建立索引,可以加快搜索的速度。
  • 在作爲主鍵的列上創建索引,強制該列的唯一性和組織表中數據數據的排列結構。
  • 在經常使用表連接的列上創建索引,這些列主要是一些外鍵,可以加快表連接的速度。
  • 在經常需要根據範圍進行搜索的列上創建索引,因爲索引已經排序,其指定的範圍是連續的。
  • 在經常需要排序的列上創建索引,因爲索引已經排序,這樣查詢可以利用索引的排序,加快排序查詢時間。
  • 在經常使用WHERE子句的列上創建索引,加快條件的判斷速度。

與此對應,在某些應用場合下建立索引不能提高MySQL工作效率,甚至在一定程度上還帶來負面效應,降低了數據庫的工作效率,一般來說不適合創建索引的環境如下:

  • 對於那些在查詢中很少使用或參考的列不應該創建索引。一是不能提高查詢速度,二是降低了系統維護速度,增大了空間需求。
  • 對於那些之只有很少數據值的列也不應該創建索引。
  • 對於那些定義爲TEXT, IMAGE和BIT數據類型的列不應該創建索引。因爲這些列的數據量要麼相當大,要麼取值很少。
  • 當修改性能遠遠大於檢索性能時,不應該創建索引。因爲修改性能和檢索性能時相互矛盾的,創建索引會提高檢索性能,降低修改性能,減少索引會提高修改性能,降低檢索性能。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章