MySQL数据库应用案例课堂
上QQ阅读APP看书,第一时间看更新

6.2 创建索引

MySQL支持用多种方法在单个或多个列上创建索引:在创建表的定义语句CREATE TABLE中指定索引列,使用ALTER TABLE语句在已有的表上创建索引或者使用CREATE INDEX语句在已有的表上添加索引。本节将详细介绍这三种方法。

6.2.1 创建表的时候创建索引

使用CREATE TABLE创建表时,除了可以定义列的数据类型外,还可以定义主键约束、外键约束或者唯一性约束,而不论创建哪种约束,在定义约束的同时都相当于在指定列上创建了一个索引。创建表时创建索引的基本语法格式如下:

  CREATE  TABLE  table_name [col_name data_type]
  [UNIQUE|FULLTEXT|SPATIAL]  [INDEX|KEY] [index_name] (col_name [length]) [ASC | DESC]

UNIQUE、FULLTEXT和SPATIAL为可选参数,分别表示唯一索引、全文索引和空间索引;INDEX与KEY为同义词,两者作用相同,用来指定创建索引;col_name为需要创建索引的字段列,该列必须从数据表中定义的多个列中选择;index_name指定索引的名称,为可选参数,如果不指定,MySQL默认col_name为索引值;length为可选参数,表示索引的长度,只有字符串类型的字段才能指定索引长度;ASC或DESC指定升序或者降序的索引值存储。

1.创建普通索引

最基本的索引类型,没有唯一性之类的限制,其作用只是加快对数据的访问速度。

【例6.1】在book表中的year_publication字段上建立普通索引,SQL语句如下:

  CREATE TABLE book
  (
    bookid               INT NOT NULL,
    bookname             VARCHAR(255) NOT NULL,
    authors              VARCHAR(255) NOT NULL,
    info                 VARCHAR(255) NULL,
    comment              VARCHAR(255) NULL,
    year_publication     YEAR NOT NULL,
    INDEX(year_publication)
  );

该语句执行完毕之后,使用SHOW CREATE TABLE查看表结构:

  mysql> SHOW CREATE table book \G
  *************************** 1. row ***************************
        Table: book
  CREATE Table: CREATE TABLE 'book' (
    'bookid' int(11) NOT NULL,
    'bookname' varchar(255) NOT NULL,
    'authors' varchar(255) NOT NULL,
    'info' varchar(255) DEFAULT NULL,
    'comment' varchar(255) DEFAULT NULL,
    'year_publication' year(4) NOT NULL,
    KEY 'year_publication' ('year_publication')
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8

由结果可以看到,book1表的year_publication字段上成功建立索引,其索引名称year_publication是MySQL自动添加的。使用EXPLAIN语句查看索引是否正在使用:

  mysql> explain select * from book where year_publication=1990 \G
  *************************** 1. row ***************************
              id: 1
      select_type: SIMPLE
           table: book
            type: ref
    possible_keys: year_publication
            key: year_publication
        key_len: 1
           ref: const
          rows: 1
         Extra:
  1 row in set (0.05 sec)

EXPLAIN语句输出结果的各行解释如下。

(1)select_type行:指定所使用的SELECT查询类型,这里值为SIMPLE,表示简单的SELECT,不使用UNION或子查询。其他可能的取值有PRIMARY、UNION、SUBQUERY等。

(2)table行:指定数据库读取的数据表的名字,它们按被读取的先后顺序排列。

(3)type行:指定本数据表与其他数据表之间的关联关系,可能的取值有system、const、eq_ref、ref、range、index和All。

(4)possible_keys行:给出MySQL在搜索数据记录时可选用的各个索引。

(5)key行:MySQL实际选用的索引。

(6)key_len行:给出索引按字节计算的长度,key_len的数值越小,表示查询速度越快。

(7)ref行:给出关联关系中另一个数据表里的数据列的名字。

(8)rows行:MySQL在执行这个查询时预计会从这个数据表里读出的数据行的个数。

(9)extra行:提供与关联操作有关的信息。

可以看到,possible_keys和key的值都为year_publication,查询时使用了索引。

2.创建唯一索引

创建索引的主要原因是为了减少查询索引列操作的执行时间。唯一索引与前面的普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。

【例6.2】创建一个表t1,在表中的id字段上使用UNIQUE关键字创建唯一索引。SQL语句如下:

  CREATE TABLE t1
  (
     id    INT NOT NULL,
     name CHAR(30) NOT NULL,
     UNIQUE INDEX UniqIdx(id)
  );

上述语句执行完毕之后,使用SHOW CREATE TABLE查看表的结构:

  mysql> SHOW CREATE table t1 \G
  *************************** 1. row ***************************
        Table: t1
  CREATE Table: CREATE TABLE 't1' (
    'id' int(11) NOT NULL,
    'name' char(30) NOT NULL,
    UNIQUE KEY 'UniqIdx' ('id')
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8
  1 row in set (0.00 sec)

由结果可以看到,id字段上已经成功建立了一个名为UniqIdx的唯一索引。

3.创建单列索引

单列索引是在数据表中的一个字段上创建的索引,一个表中可以创建多个单列索引。前面两个例子中创建的索引都为单列索引。

【例6.3】创建一个表t2,在表中的name字段上创建单列索引。SQL语句如下:

  CREATE TABLE t2
  (
     id   INT NOT NULL,
     name CHAR(50) NULL,
     INDEX SingleIdx(name(20))
  );

上述语句执行完毕之后,使用SHOW CREATE TABLE查看表的结构:

  mysql> SHOW CREATE table t2 \G
  *************************** 1. row ***************************
        Table: t2
  CREATE Table: CREATE TABLE 't2' (
    'id' int(11) NOT NULL,
    'name' char(50) DEFAULT NULL,
    KEY 'SingleIdx' ('name'(20))
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8

由结果可以看到,id字段上已经成功建立了一个名为SingleIdx的单列索引,索引的长度为20。

4.创建组合索引

组合索引是在多个字段上创建的索引。

【例6.4】创建表t3,在表中的id、name和age字段上建立组合索引,SQL语句如下:

  CREATE TABLE t3
  (
     id    INT NOT NULL,
     name CHAR(30)  NOT NULL,
     age  INT NOT  NULL,
     info VARCHAR(255),
     INDEX MultiIdx(id, name, age(100))
  );

上述语句执行完毕之后,使用SHOW CREATE TABLE查看表的结构:

  mysql> SHOW CREATE table t3 \G
  *************************** 1. row ***************************
        Table: t3
  CREATE Table: CREATE TABLE 't3' (
    'id' int(11) NOT NULL,
    'name' char(30) NOT NULL,
    'age' int(11) NOT NULL,
    'info' varchar(255) DEFAULT NULL,
    KEY 'MultiIdx' ('id','name','age')
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8

由结果可以看到,id、name和age字段上已经成功建立了一个名为MultiIdx的组合索引。

提示 组合索引可起到几个索引的作用,但是使用时并不是随便查询哪个字段都可以使用索引,而是要遵从“最左前缀”原则:利用索引中最左边的列集来匹配行,这样的列集称为最左前缀。例如,这里由id、name和age三个字段构成的索引,索引行中按id/name/age的顺序存放,索引可以搜索下面的字段组合:(id, name, age)、(id, name)或者id。

在t3表中,查询id和name字段,使用EXPLAIN语句查看索引的使用情况:

  mysql> explain select * from t3 where id=1 AND name='joe' \G
  *************************** 1. row ***************************
             id: 1
     select_type: SIMPLE
          table: t3
           type: ref
   possible_keys: MultiIdx
           key: MultiIdx
        key_len: 94
           ref: const,const
          rows: 1
         Extra: Using where
  1 row in set (0.00 sec)

可以看到,查询id和name字段时,使用了名称为MultiIdx的索引;如果查询(name,age)组合或者单独查询name和age字段,结果如下:

  *************************** 1. row ***************************
            id: 1
    select_type: SIMPLE
         table: t3
          type: ALL
  possible_keys: NULL
          key: NULL
       key_len: NULL
          ref: NULL
         rows: 1
        Extra: Using where

此时,possible_keys和key的值为NULL,表示未使用在t3表中创建的索引进行查询。

5.创建全文索引

FULLTEXT全文索引可用于全文搜索。只有MyISAM存储引擎支持FULLTEXT索引,并且只能在数据类型为CHAR、VARCHAR和TEXT的列上建立全文索引。

【例6.5】创建表t4,在表中的info字段上建立全文索引,SQL语句如下:

  CREATE TABLE t4
  (
     id    INT NOT NULL,
     name CHAR(30) NOT NULL,
     age  INT NOT NULL,
     info VARCHAR(255),
     FULLTEXT INDEX FullTxtIdx(info)
  ) ENGINE=MyISAM;

提示 因为MySQL 5.6中的默认存储引擎为InnoDB,在这里创建表时需要将表的存储引擎改为MyISAM,不然创建全文索引时会出错。

上述语句执行完毕之后,使用SHOW CREATE TABLE查看表的结构:

  mysql> SHOW CREATE table t4 \G
  *************************** 1. row ***************************
        Table: t4
  CREATE Table: CREATE TABLE 't4' (
    'id' int(11) NOT NULL,
    'name' char(30) NOT NULL,
    'age' int(11) NOT NULL,
    'info' varchar(255) DEFAULT NULL,
    FULLTEXT KEY 'FullTxtIdx' ('info')
  ) ENGINE=MyISAM DEFAULT CHARSET=utf8

由结果可以看到,info字段上已经成功建立了一个名为FullTxtIdx的FULLTEXT索引。全文索引非常适合在大型数据集中使用,对于小的数据集,它的用处可能比较小。

6.创建空间索引

空间索引必须在MyISAM类型的表中创建,且空间类型的字段不能为空。

【例6.6】创建表t5,在空间类型为GEOMETRY的字段上创建空间索引,SQL语句如下:

  CREATE TABLE t5
  ( g GEOMETRY NOT NULL, SPATIAL INDEX spatIdx(g) )ENGINE=MyISAM;

上述语句执行完毕之后,使用SHOW CREATE TABLE查看表的结构:

  mysql> SHOW CREATE table t5 \G
  *************************** 1. row ***************************
        Table: t5
  CREATE Table: CREATE TABLE 't5' (
    'g' geometry NOT NULL,
    SPATIAL KEY 'spatIdx' ('g')
  ) ENGINE=MyISAM DEFAULT CHARSET=utf8

可以看到,t5表的g字段上创建了名称为spatIdx的空间索引。注意创建时要指定空间类型字段值的非空约束,并且表的存储引擎要为MyISAM。

6.2.2 在已有的表上创建索引

在已有的表中创建索引,可以使用ALTER TABLE语句或者CREATE INDEX语句。本节将介绍如何使用ALTER TABLE和CREATE INDEX语句在已知表的字段上创建索引。

1.使用ALTER TABLE语句创建索引

用ALTER TABLE语句创建索引的基本语法如下:

  ALTER TABLE table_name  ADD [UNIQUE|FULLTEXT|SPATIAL]  [INDEX|KEY]
  [index_name] (col_name[length],…) [ASC | DESC]

与创建表时创建索引的语法不同的是,在这里使用了ALTER TABLE和ADD关键字,ADD表示向表中添加索引。

【例6.7】在book表中的bookname字段上建立名为BkNameIdx的普通索引。

SQL语句如下:

  ALTER TABLE book ADD INDEX BkNameIdx ( bookname(30) );

添加索引之前,先使用SHOW INDEX语句查看指定表中创建的索引:

  mysql> SHOW INDEX FROM book \G
  *************************** 1. Row ***************************
            Table: book
       Non_unique: 1
         Key_name: year_publication
     Seq_in_index: 1
      Column_name: year_publication
        Collation: A
      Cardinality: 0
         Sub_part: NULL
           Packed: NULL
              Null:
      Index_type: BTREE
         Comment:
  Index_comment:

上面各主要参数的含义如下。

(1)Table:表示创建索引的表。

(2)Non_unique:表示索引非唯一,1代表非唯一索引,0代表唯一索引。

(3)Key_name:表示索引的名称。

(4)Seq_in_index:表示该字段在索引中的位置,单列索引该值为1,组合索引为每个字段在索引定义中的顺序。

(5)Column_name:表示定义索引的列字段。

(6)Sub_part:表示索引的长度。

(7)Null:表示该字段是否能为空值。

(8)Index_type:表示索引类型。

可以看到,book表中有一个索引,即前面已经定义的名称为year_publication的索引,该索引为非唯一索引。

下面使用ALTER TABLE语句在bookname字段上添加索引,SQL语句如下:

  ALTER TABLE book ADD INDEX BkNameIdx( bookname(30) );

使用SHOW INDEX语句查看表中的索引:

  mysql> SHOW INDEX FROM book \G
  *************************** 1. Row ***************************
            Table: book
       Non_unique: 1
         Key_name: year_publication
     Seq_in_index: 1
      Column_name: year_publication
        Collation: A
      Cardinality: 0
         Sub_part: NULL
           Packed: NULL
              Null:
      Index_type: BTREE
         Comment:
  Index_comment:
  *************************** 2. Row ***************************
            Table: book
       Non_unique: 1
         Key_name: BkNameIdx
     Seq_in_index: 1
      Column_name: bookname
        Collation: A
      Cardinality: 0
          Sub_part: 30
           Packed: NULL
              Null:
      Index_type: BTREE
         Comment:
  Index_comment:

可以看到,现在表中又新增了一个索引,即通过ALTER TABLE语句添加的名称为BkNameIdx的索引,该索引为非唯一索引,长度为30。

【例6.8】在book表的bookId字段上建立名称为UniqidIdx的唯一索引。

SQL语句如下:

  ALTER TABLE book ADD UNIQUE INDEX UniqidIdx ( bookId );

使用SHOW INDEX语句查看表中的索引:

  mysql> SHOW INDEX FROM book \G
  *************************** 1. Row ***************************
            Table: book
       Non_unique: 0
         Key_name: UniqidIdx
     Seq_in_index: 1
      Column_name: bookid
        Collation: A
      Cardinality: 0
         Sub_part: NULL
           Packed: NULL
              Null:
      Index_type: BTREE
         Comment:
  Index_comment:

可以看到Non_unique属性的值为0,表示名称为UniqidIdx的索引为唯一索引,创建唯一索引成功。

【例6.9】在book表的comment字段上建立单列索引。

SQL语句如下:

  ALTER TABLE book ADD INDEX BkcmtIdx ( comment(50) );

使用SHOW INDEX语句查看表中的索引:

  *************************** 3. Row ***************************
            Table: book
       Non_unique: 1
         Key_name: BkcmtIdx
     Seq_in_index: 1
      Column_name: comment
        Collation: A
      Cardinality: 0
         Sub_part: 50
           Packed: NULL
              Null: YES
      Index_type: BTREE
         Comment:
  Index_comment:

可以看到,语句执行之后在book表的comment字段上建立了名为BkcmgIdx的索引,长度为50,在查询时,只需要检索前50个字符。

【例6.10】在book表的authors和info字段上建立组合索引。

SQL语句如下:

  ALTER TABLE book ADD INDEX BkAuAndInfoIdx ( authors(20),info(50) );

使用SHOW INDEX语句查看表中的索引:

  mysql> SHOW INDEX FROM book \G
  *************************** 4. Row ***************************
            Table: book
       Non_unique: 1
         Key_name: BkAuAndInfoIdx
     Seq_in_index: 1
      Column_name: authors
        Collation: A
      Cardinality: 0
         Sub_part: 30
           Packed: NULL
              Null:
      Index_type: BTREE
         Comment:
  Index_comment:
  *************************** 5. Row ***************************
            Table: book
       Non_unique: 1
         Key_name: BkAuAndInfoIdx
     Seq_in_index: 2
      Column_name: info
        Collation: A
      Cardinality: 0
         Sub_part: 50
           Packed: NULL
              Null: YES
      Index_type: BTREE
         Comment:
  Index_comment:

可以看到名称为BkAuAndInfoIdx的索引由两个字段组成:authors字段长度为30,在组合索引中的序号为1,该字段不允许空值NULL;info字段长度为50,在组合索引中的序号为2,该字段可以为空值NULL。

【例6.11】创建表t6,在t6表上使用ALTER TABLE创建全文索引。

首先创建表t6,语句如下:

  CREATE TABLE t6
  (
     id    INT NOT NULL,
     info  CHAR(255)
  ) ENGINE=MyISAM;

注意修改ENGINE参数为MyISAM,MySQL中的默认引擎InnoDB不支持全文索引。

使用ALTER TABLE语句在info字段上创建全文索引:

  ALTER TABLE t6 ADD FULLTEXT INDEX infoFTIdx ( info );

使用SHOW INDEX语句查看索引:

  mysql> SHOW index from t6 \G
  ************************** 1. Row ***************************
         Table: t6
    Non_unique: 1
      Key_name: infoFTIdx
  Seq_in_index: 1
   Column_name: info
     Collation: NULL
   Cardinality: NULL
      Sub_part: NULL
        Packed: NULL
          Null: YES
    Index_type: FULLTEXT
       Comment:
  ndex_comment:

可以看到,t6表中已经创建了名为infoFTIdx的索引,该索引在info字段上创建,类型为FULLTEXT,允许空值。

【例6.12】创建表t7,在t7的空间数据类型字段g上创建名为spatIdx的空间索引。

SQL语句如下:

  CREATE TABLE t7 ( g GEOMETRY NOT NULL )ENGINE=MyISAM;

使用ALTER TABLE在表t7的g字段建立空间索引:

  ALTER TABLE t7 ADD SPATIAL INDEX spatIdx(g);

使用SHOW INDEX语句查看索引:

  mysql> SHOW index from t7 \G
  *************************** 1. Row ***************************
            Table: t7
       Non_unique: 1
         Key_name: spatIdx
     Seq_in_index: 1
      Column_name: g
        Collation: A
      Cardinality: NULL
         Sub_part: 32
           Packed: NULL
              Null:
      Index_type: SPATIAL
         Comment:
  Index_comment:

可以看到,t7表中的g字段上创建了名为spatIdx的空间索引。

2.使用CREATE INDEX创建索引

用CREATE INDEX语句可以在已有的表上添加索引,基本语法结构如下:

  CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name
  ON table_name (col_name[length],…) [ASC | DESC]

可以看到CREATE INDEX语句和ALTER INDEX语句的语法基本一样,只是关键字不同。

在这里,使用相同的表book,假设该表中没有任何索引值,创建book表的语句如下:

  CREATE TABLE book
  (
     bookid            INT NOT NULL,
     bookname          VARCHAR(255) NOT NULL,
     authors           VARCHAR(255) NOT NULL,
     info              VARCHAR(255) NULL,
     comment           VARCHAR(255) NULL,
     year_publication      YEAR NOT NULL
  );

提示 读者可以将该数据库中的book表删除,按上面的语句重新建立,然后进行下面的操作。

【例6.13】在book表中的bookname字段上建立名为BkNameIdx的普通索引。

SQL语句如下:

  CREATE INDEX BkNameIdx ON book(bookname);

上述语句执行完毕之后,将在book表中创建名为BkNameIdx的普通索引。读者可以用SHOW INDEX或者SHOW CREATE TABLE语句查看book表中的索引,其索引内容与前面介绍的相同。

【例6.14】在book表的bookId字段上建立名为UniqidIdx的唯一索引。

SQL语句如下:

  CREATE UNIQUE INDEX UniqidIdx  ON book ( bookId );

语句执行完毕之后,将在book表中创建名为UniqidIdx的唯一索引。

【例6.15】在book表的comment字段上建立单列索引。

SQL语句如下:

  CREATE INDEX BkcmtIdx ON book(comment(50) );

语句执行完毕之后,将在book表的comment字段上建立一个名为BkcmtIdx的单列索引,长度为50。

【例6.16】在book表的authors和info字段上建立组合索引。

SQL语句如下:

  CREATE INDEX BkAuAndInfoIdx ON book ( authors(20),info(50) );

语句执行完毕之后,将在book表的authors和info字段上建立一个名为BkAuAndInfoIdx的组合索引。authors的索引序号为1,长度为20;info的索引序号为2,长度为50。

【例6.17】删除表t6,重新建立表t6,在t6表中使用CREATE INDEX语句,在CHAR类型的info字段上创建全文索引。

首先删除表t6,并重新建立该表,分别输入下面语句:

  mysql> drop table t6;
  Query OK, 0 rows affected (0.00 sec)
  
  mysql> CREATE TABLE t6
      -> (
      -> id    INT NOT NULL,
      -> info  CHAR(255)
      -> ) ENGINE=MyISAM;
  Query OK, 0 rows affected (0.00 sec)

使用CREATE INDEX语句在t6表的info字段上创建名为infoFTIdx的全文索引:

  CREATE FULLTEXT INDEX ON t6(info);

语句执行完毕之后,将在t6表中创建名为infoFTIdx的索引,该索引在info字段上创建,类型为FULLTEXT,允许空值。

【例6.18】删除表t7,重新创建表t7,在t7表中用CREATE INDEX语句在空间数据类型字段g上创建名为spatIdx的空间索引。

首先删除表t7,并重新建立该表,分别输入下面语句:

  mysql> drop table t7;
  Query OK, 0 rows affected (0.00 sec)
  
  mysql> CREATE TABLE t7 ( g GEOMETRY NOT NULL )ENGINE=MyISAM;
  Query OK, 0 rows affected (0.00 sec)

用CREATE INDEX语句在表t7中的g字段上建立空间索引:

  CREATE SPATIAL INDEX spatIdx ON t7 (g);

语句执行完毕之后,将在t7表中创建名为spatIdx的空间索引,该索引在g字段上创建。