數據庫索引就象書的目錄一樣,如果在字段上建立了索引,那么以索引列為查詢條件時 可以加快查詢數據的速度 查詢數據庫,按主鍵查詢是最快的,每個表只能有一個主鍵列,但是可以有多個普通索 引列,主鍵列要求列的所有內容必須唯一,而普通索引列不要求內容必須唯一 主鍵就類似我們在學校學習時的學號一樣,班級里是唯一的,整個表的每一條記錄的 鍵值在表內都是唯一的,用來唯一標識一條記錄。
12.1 為表創建主鍵索引的方法
mysql> use oldboy Database changed mysql> create table student( -> id int(4) not null AUTO_INCREMENT, -> name char(20) not null, -> age tinyint(2) not null default '0', -> dept varchar(16) default null, ->primary key(id), ->KEY index_name(name) ->);
提示:
primary key(id) <-主鍵
KEY index_name(name) <-name 字段普通索引
只有 int 類型且為 primary key 才可以使用 auto_increment
12.2 查看 student 表的結構
mysql> show create table student\G; *************************** 1. row *************************** Table: student Create Table: CREATE TABLE `student` ( `id` int(4) NOT NULL AUTO_INCREMENT, `name` char(20) NOT NULL, `age` tinyint(2) NOT NULL DEFAULT '0', `dept` varchar(16) DEFAULT NULL, PRIMARY KEY (`id`), KEY `index_name` (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 1 row in set (0.00 sec) ERROR: No query specified mysql> describe student; +-------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+----------------+ | id | int(4) | NO | PRI | NULL | auto_increment | | name | char(20) | NO | MUL | NULL | | | age | tinyint(2) | NO | | 0 | | | dept | varchar(16) | YES | | NULL | | +-------+-------------+------+-----+---------+----------------+ 4 rows in set (0.00 sec)
12.3 怎么刪除一個表的主鍵
mysql> alter table student drop primary key;
提示:如果一個表中的 primary key 設置了 AUTO_INCREMENT(自動增加)的話,就刪不掉
12.4 利用 alter 命令修改 id 列為自增主鍵列
mysql> alter table student change id id int primary key auto_increment;
12.5 建表后利用 alter 增加普通索引
刪除建表時創建的 index_name 索引 mysql> select database(); +------------+ | database() +------------+ | oldboy | +------------+ 1 row in set (0.00 sec) mysql> show create table student; +---------+---------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------- --------------------------------+ | Table | Create Table | +---------+---------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------- --------------------------------+ | student | CREATE TABLE `student` ( `id` int(4) NOT NULL AUTO_INCREMENT, `name` char(20) NOT NULL, `age` tinyint(2) NOT NULL DEFAULT '0', `dept` varchar(16) DEFAULT NULL, PRIMARY KEY (`id`), KEY `index_name` (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 | +---------+---------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------- --------------------------------+ 1 row in set (0.00 sec) 刪除普通索引 mysql> alter table student drop index index_name; Query OK, 0 rows affected (0.08 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> show create table student; +---------+---------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------- ---+ | Table | Create Table | +---------+---------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------- ---+ | student | CREATE TABLE `student` ( `id` int(4) NOT NULL AUTO_INCREMENT, `name` char(20) NOT NULL, `age` tinyint(2) NOT NULL DEFAULT '0', `dept` varchar(16) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 | +---------+---------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------- ---+ 1 row in set (0.00 sec) 創建普通索引 mysql> use oldboy Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> alter table student add index index_name (name); Query OK, 0 rows affected (0.47 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> show create table student; +---------+---------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------- --------------------------------+ | Table | Create Table | +---------+---------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------- --------------------------------+ | student | CREATE TABLE `student` ( `id` int(4) NOT NULL AUTO_INCREMENT, `name` char(20) NOT NULL, `age` tinyint(2) NOT NULL DEFAULT '0', `dept` varchar(16) DEFAULT NULL, PRIMARY KEY (`id`), KEY `index_name` (`name`) 提示:訪問數據量很大的時候,不適合建立普通索引,會影響 用戶訪問,盡量選擇業務低估時建立索引 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 | +---------+---------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------- --------------------------------+ 1 row in set (0.00 sec)
12.6 對表字段的前 n 個字符創建普通索引
當遇到表中比較大的列時,列內容的前 n 個字符在所有內容中已接近唯一時,這時可以對列的前 n 個字符建立索引,而無需對整個列建立本索引,這樣可以節省創建索引占用的系統空間,以及降低讀取和更新維護索引消耗的系統資源。
對字段前 n 個字符創建普通索引的語法:
create index index_name on student(name(8));條件列前 N 個字符創建索引
下面來實戰演示:
mysql> select database(); +------------+ | database() | +------------+ | oldboy | +------------+ 1 row in set (0.00 sec) 為 dept 列前八個字符創建普通索引 mysql> describe student; +-------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+----------------+ | id | int(4) | NO | PRI | NULL | auto_increment | | name | char(20) | NO | MUL | NULL | | | age | tinyint(2) | NO | | 0 | | | dept | varchar(16) | YES | | NULL | | +-------+-------------+------+-----+---------+----------------+ 4 rows in set (0.00 sec) mysql> create index index_name_dept on student (dept(8)); Query OK, 0 rows affected (0.21 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> describe student; +-------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+----------------+ | id | int(4) | NO | PRI | NULL | auto_increment | | name | char(20) | NO | MUL | NULL | | | age | tinyint(2) | NO | | 0 | | | dept | varchar(16) | YES | MUL | NULL | | +-------+-------------+------+-----+---------+----------------+ 4 rows in set (0.00 sec) mysql> show create table student; +---------+---------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------+ | Table | Create Table | +---------+---------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------+ | student | CREATE TABLE `student` ( `id` int(4) NOT NULL AUTO_INCREMENT, `name` char(20) NOT NULL, `age` tinyint(2) NOT NULL DEFAULT '0', `dept` varchar(16) DEFAULT NULL, PRIMARY KEY (`id`), KEY `index_name` (`name`), KEY `index_name_dept` (`dept`(8)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 | +---------+---------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------+ 1 row in set (0.00 sec)
另外一種建立表后創建普通索引的方法:
mysql> alter table student add index index_name_dept (dept(8));
12.7 為表的多個字段創建聯合索引
如何查詢數據的條件時多列時,我們可以為多個查詢的列創建聯合索引,甚至,可以為多列的前 n 個字符列創建聯合索引,實戰演示如下:
mysql> create index index_name_and_dept on student (name,dept); Query OK, 0 rows affected (0.11 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> show create table student; +---------+---------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +---------+---------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------+ | student | CREATE TABLE `student` ( `id` int(4) NOT NULL AUTO_INCREMENT, `name` char(20) NOT NULL, `age` tinyint(2) NOT NULL DEFAULT '0', `dept` varchar(16) DEFAULT NULL, PRIMARY KEY (`id`), KEY `index_name` (`name`), KEY `index_name_dept` (`dept`(8)), KEY `index_name_and_dept` (`name`,`dept`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 | +---------+---------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec)
12.8 為表的多個字段的前 n 個字符創建聯合索引
mysql> create index index_name_and_dept on student (name(10),dept(10)); Query OK, 0 rows affected (0.03 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> show create table student; +---------+---------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------- ----+ | Table | Create Table | +---------+---------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------- ----+ | student | CREATE TABLE `student` ( `id` int(4) NOT NULL AUTO_INCREMENT, `name` char(20) NOT NULL, `age` tinyint(2) NOT NULL DEFAULT '0', `dept` varchar(16) DEFAULT NULL, PRIMARY KEY (`id`), KEY `index_name` (`name`), KEY `index_name_dept` (`dept`(8)), KEY `index_name_and_dept` (`name`(10),`dept`(10)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 | +---------+---------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------- ----+ 1 row in set (0.00 sec)
提示:按條件列查詢數據時,聯合索引是有前綴生效特性的
index(a,b,c)僅 a,ab,abc 三個查詢條件列可以走索引,b,bc,ac,c 等無法使用索引了
盡量把最常用作為查詢條件的列,放在第一位置
12.9 主鍵也可以聯合多列做索引
*************************** 1. row *************************** Table: user Create Table: CREATE TABLE `user` ( `Host` char(60) COLLATE utf8_bin NOT NULL DEFAULT '', `User` char(16) COLLATE utf8_bin NOT NULL DEFAULT '', `Password` char(41) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL DEFAULT '', `Select_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Insert_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Update_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Delete_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Create_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Drop_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Reload_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Shutdown_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Process_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `File_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Grant_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `References_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Index_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Alter_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Show_db_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Super_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Create_tmp_table_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Lock_tables_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Execute_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Repl_slave_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Repl_client_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Create_view_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Show_view_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Create_routine_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Alter_routine_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Create_user_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Event_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Trigger_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `Create_tablespace_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N', `ssl_type` enum('','ANY','X509','SPECIFIED') CHARACTER SET utf8 NOT NULL DEFAULT '', `ssl_cipher` blob NOT NULL, `x509_issuer` blob NOT NULL, `x509_subject` blob NOT NULL, `max_questions` int(11) unsigned NOT NULL DEFAULT '0', `max_updates` int(11) unsigned NOT NULL DEFAULT '0', `max_connections` int(11) unsigned NOT NULL DEFAULT '0', `max_user_connections` int(11) unsigned NOT NULL DEFAULT '0', `plugin` char(64) COLLATE utf8_bin DEFAULT '', `authentication_string` text COLLATE utf8_bin, PRIMARY KEY (`Host`,`User`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Users and global privileges' 1 row in set (0.00 sec) ERROR: No query specified
12.10 統計一個字段列的唯一值個數
-
mysql> select user from mysql.user; +-----------+ | user | +-----------+ | root | | blog | | oldgirl | | wordpress | | oldgirl | | oldboy | | oldgirl | | root | +-----------+ 8 rows in set (0.00 sec) mysql> select count(distinct user) from mysql.user; +----------------------+ | count(distinct user) | +----------------------+ | 5 | +----------------------+ 1 row in set (0.06 sec) 提示:盡量在唯一值多的大表上建立索引
12.11 創建唯一索引(非主鍵)
mysql> show create table student ; +---------+---------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------- --------------------------------------+ | Table | Create Table | +---------+---------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------- --------------------------------------+ | student | CREATE TABLE `student` ( `id` int(4) NOT NULL AUTO_INCREMENT, `name` char(20) NOT NULL, `age` tinyint(2) NOT NULL DEFAULT '0', `dept` varchar(16) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `index_age` (`age`), KEY `index_name` (`name`), KEY `index_name_dept` (`dept`(8)), KEY `index_name_and_dept` (`name`(10),`dept`(10)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 | +---------+---------------------------------------------------------------------------------------------------------- 1 row in set (0.00 sec)
12.12 索引列的創建及生效條件
問題一:既然索引可以加快查詢速度,那么就給所有的列建索引吧?
解答:因為索引不但占用系統空間,而且更新數據時還需要維護索引數據的,因此,索引是一把雙刃劍,並不是越多越好,例如:數十到幾百行的小表上無需建立索引,更新頻繁,讀取比較少的表要少建立索引
問題二:需要在哪些列上創建索引了?
解答:select user,host from mysql.user where password=...,索引一定要創建在 where 后的條件列上,而不是 select 后的選擇數據的列上,另外,我們要盡量選擇在唯一值多的大表上的列建立索引,例如:男女性別列唯一值,不適合建立索引