天天看点

mysql 视图的索引吗_MySQL数据库的视图与索引

mysql视图机制

什么是视图

视图是一张虚拟的表,为什么是虚拟呢?因为视图与数据库中存在的表不太一样,前面我们创建的4张表都是包含数据的,如用户信息,订单信息等,而视图则是不包含数据的,下面通过一个例子来演示视图,下面的sql是查询王五的所有订单情况,需要关联到orders表、orderdetail表、items表、user表

mysql> select u.username , o.number , tm.name as itemsName , tm.price , od.items_num from

-> (

-> (orders as o inner join orderdetail as od on o.id = od.orders_id )

-> inner join items as tm on od.items_id = tm.id

-> )

-> inner join user as u on o.user_id = u.id

-> where username='王五';

+----------+---------+-------------+---------+-----------+

| username | number | name | price | items_num |

+----------+---------+-------------+---------+-----------+

| 王五 | 1000010 | MacBook Air | 8298.9 | 1 |

| 王五 | 1000010 | MacBook Pro | 10982.0 | 3 |

| 王五 | 1000011 | 背包 | 200.0 | 4 |

| 王五 | 1000011 | MacBook Pro | 10982.0 | 3 |

+----------+---------+-------------+---------+-----------+

4 rows in set (0.01 sec)

显然数据已如期查询出来了,但是我们发现任何需要这个数据的人都必须了解相关联的表结构,并且需要知道如何创建查询和对表进行联结,为了检索其他用户的相同数据必须修改Where条件并带上一大段关联查询的sql语句。是的,每次这样的操作确实挺麻烦的,假如现在可以把这个除了where条件外的sql查询出来的数据包装成一个名为user_order_data的虚拟表,就可以使用以下方式检索出数据了。

select * from user_order_data where username='王五';

按这样的方式每次查询不同的用户只需修改where条件即可也不同再写那段看起有点恶心的长sql了,而事实上user_order_data就是一张视图表,也可称为虚拟表,而这就是视图最显著的作用了。

视图创建与使用

了解完什么是视图后,我们先来看看如何创建视图和使用视图,使用以下语法:

CREATE VIEW 视图名(列名,...) AS SELECT 语句

现在我们使用前面关联查询的orders表、orderdetail表、items表、user表来创建视图user_order_data

-- 创建视图虚拟表user_order_data

mysql> create view user_order_data(username,number,itemname,price,items_num) as select u.username , o.number , tm.name , tm.price , od.items_num from

-> (

-> (orders as o inner join orderdetail as od on o.id = od.orders_id )

-> inner join items as tm on od.items_id = tm.id

-> )

-> inner join user as u on o.user_id = u.id;

Query OK, 0 rows affected (0.01 sec)

-- 使用视图

mysql> select * from user_order_data;

+----------+---------+-------------+---------+-----------+

| username | number | itemname | price | items_num |

+----------+---------+-------------+---------+-----------+

| 王五 | 1000010 | MacBook Air | 8298.9 | 1 |

| 王五 | 1000010 | MacBook Pro | 10982.0 | 3 |

| 王五 | 1000011 | 背包 | 200.0 | 4 |

| 王五 | 1000011 | MacBook Pro | 10982.0 | 3 |

+----------+---------+-------------+---------+-----------+

4 rows in set (0.01 sec)

可以看出除了在select语句前面加上create view user_order_data as外,其他几乎没变化。在使用视图user_order_data时,跟使用数据库表没啥区别,因此以后需要查询指定用户或者所有用户的订单情况时,就不用编写长巴巴的一段sql了,还是蛮简洁的。除了上述的方式,还可以将视图虚拟表的字段别名移动到查询字段后面:

CREATE OR REPLACE VIEW user_order_data

AS

SELECT

u.username as username,

o.number as number ,

tm.name as name ,

tm.price as price ,

od.items_num as items_num

FROM

(

(orders as o INNER JOIN orderdetail as od ON o.id = od.orders_id )

INNER JOIN items as tm ON od.items_id = tm.id

)

INNER JOIN user as u ON o.user_id = u.id

注意这里使用了CREATE OR REPLACE VIEW语句,意思就是不存在就创建,存在就替换。如果想删除视图可以使用以下语法:

DROP VIEW 视图名称

1

在使用视图的过程还有些需要注意的点,如下

与创建表一样,创建视图的名称必须唯一

创建视图的个数并没限制,但是如果一张视图嵌套或者关联的表过多,同样会引发性能问题,在实际生产环节中部署时务必进行必要的性能检测。

在过滤条件数据时如果在创建视图的sql语句中存在where的条件语句,而在使用该视图的语句中也存在where条件语句时,这两个where条件语句会自动组合

order by 可以在视图中使用,但如果从该视图检索数据的select语句中也含有order by ,那么该视图中的order by 将被覆盖。

视图中不能使用索引,也不能使用触发器(索引和触发器后面会分析)

使用可以和普通的表一起使用,编辑一条联结视图和普通表的sql语句是允许的。

关于使用视图对数据的进行更新(增删改),因为视图本身并没有数据,所以这些操作都是直接作用到普通表中的,但也并非所有的视图都可以进行更新操作,如视图中存在分组(group by)、联结、子查询、并(unoin)、聚合函数(sum/count等)、计算字段、DISTINCT等都不能对视图进行更新操作,因此我们前面的例子也是不能进行更新操作的,事实上,视图更多的是用于数据检索而更新,因此对于更新也没有必要进行过多阐述。

视图的本质

到此对于视图的创建和使用都比较清晰了,现在准备进一步认识视图的本质,前面我们反复说过,视图是一张虚拟表,是不带任何数据的,每次查询时只是从普通表中动态地获取数据并组合,只不过外表看起来像一张表罢了。其原理通过下图便一目了然:

mysql 视图的索引吗_MySQL数据库的视图与索引

事实上有些时候视图还会被用于限制用户对普通表的查询操作,对于这类用户只赋予对应视图的select操作权限,仅让他们只能读取特定的行或列的数据。这样我们也就不用直接使用数据库的权限设置限制行列的读取,同时也避免了权限细化的麻烦。

高效索引

使用索引的理由

由于mysql在默认情况下,表中的数据记录是没有顺序可言的,也就是说在数据检索过程中,符合条件的数据存储在哪里,我们是完全不知情的,如果使用select语句进行查询,数据库会从第一条记录开始检索,即使找到第一条符合条件的数据,数据库的搜索也并不会因此而停止,毕竟符合条件的数据可能并不止一条,也就是说此时检索会把表中的数据全部检索一遍才结束,这样的检索方式也称为全表扫描。但假设表中存在上百上千万条数据呢?这样的检索效率就十分低了,为了解决这个问题,索引的概念就诞生了,索引是为检索而存在的。如一些书的末尾一般会提供专门附录索引,指明了某个关键字在正文中的出现的页码位置或章节的位置,这样只要找到对应页面就能找到要搜索的内容了,数据库的索引也是类似这样的原理,通过创建某个字段或者多个字段的索引,在搜索该字段时就可以根据对应的索引进行快速检索出相应内容而无需全表扫描了。

索引的创建及其基本类型

MySQL 索引可以分为单列索引、复合索引、唯一索引、主键索引等。下面分别介绍

单列索引

单列索引,也称为普通索引,单列索引是最基本的索引,它没有任何限制,创建一个单列索引,语法如下:

CREATE INDEX index_name ON tbl_name(index_col_name);

1

其中index_name为索引的名称,可以自定义,tbl_name则指明要创建索引的表,而index_col_name指明表中那一个列要创建索引。当然我们也可以通过修改表结构的方式添加索引:

ALTER TABLE tbl_name ADD INDEX index_name ON (index_col_name);

1

还可在创建表时直接指定:

-- 创建表时直接指定

CREATE TABLE `table` (

`id` int(11) NOT NULL AUTO_INCREMENT ,

`name` varchar(32) NOT NULL ,

...... -- 其他字段

PRIMARY KEY (`id`),

indexName (name(32)) -- 创建name字段索引

);

下面为user表的username字段创建单列索引:

-- 创建username字段的索引名称为index_name,这就是基础的索引创建

mysql> create index index_name on user(username);

Query OK, 0 rows affected (0.16 sec)

Records: 0 Duplicates: 0 Warnings: 0

-- 查看user表存在的索引 \G 代表优化显示方式

mysql> show index from user \G;

*************************** 1. row ***************************

Table: user 表名称

Non_unique: 0 索引是否允许重复(1:可重复,0:不可重复)

Key_name: PRIMARY 索引名称

Seq_in_index: 1

Column_name: id 表中被创建索引的字段名称

Collation: A 是否排序(A:升序,Null:不排序)

Cardinality: 9

Sub_part: NULL

Packed: NULL

Null:

Index_type: BTREE 索引的类型

Comment:

Index_comment:

*************************** 2. row ***************************

Table: user

Non_unique: 1 索引是否允许重复(1:可重复,0:不可重复)

Key_name: index_name 索引名称

Seq_in_index: 1

Column_name: username 表中被创建索引的字段名称

Collation: A 是否排序(A:升序,Null:不排序)

Cardinality: 9

Sub_part: NULL

Packed: NULL

Null:

Index_type: BTREE 索引的类型

Comment:

Index_comment:

2 rows in set (0.00 sec)

可见user表中的username字段的索引已被创建,在使用show index from user查看user的索引字段时,我们发现id字段也创建了索引,事实上,当user表被创建时,主键的定义的字段id就会自动创建索引,这是一种特殊的索引,也称为丛生索引,而刚才创建的index_name索引属于单列索引

复合索引

复合索引:复合索引是在多个字段上创建的索引。复合索引遵守“最左前缀”原则,即在查询条件中使用了复合索引的第一个字段,索引才会被使用。因此,在复合索引中索引列的顺序至关重要。创建一个复合索引的语法如下:

-- index_name代表索引名称,而index_col_name1和index_col_name2为列名,可以多个

CREATE INDEX index_name ON tbl_name(index_col_name1,index_col_name2,...);

-- 同样道理,也可以通过修改表结构的方式添加索引,

ALTER TABLE tbl_name ADD INDEX index_name ON (index_col_name1,index_col_name2,...);

-- 创建表时直接指定

CREATE TABLE `table` (

`id` int(11) NOT NULL AUTO_INCREMENT ,

`name` varchar(32) NOT NULL ,

'pinyin' varchar(32) ,

...... -- 其他字段

PRIMARY KEY (`id`),

indexName (name(32),pinyin(32))

);

为了方便演示,为user表添加名称拼音字段(pinyin)

-- 添加新字段pinyin

mysql> alter table user add pinyin varchar(32) after username;

Query OK, 0 rows affected (0.12 sec)

Records: 0 Duplicates: 0 Warnings: 0

现在利用username和pinyin 两个字段为user表创建复合索引,先删除之前为username创建的索引,删除索引语法如下:

DROP INDEX 索引名称 ON 表名

删除username的索引

-- 删除index_name索引

mysql> drop index index_name on user;

Query OK, 0 rows affected (0.01 sec)

Records: 0 Duplicates: 0 Warnings: 0

-- 查看user的索引

mysql> show index from user \G;

*************************** 1. row ***************************

Table: user

Non_unique: 0

Key_name: PRIMARY

Seq_in_index: 1

Column_name: id

Collation: A

Cardinality: 7

Sub_part: NULL

Packed: NULL

Null:

Index_type: BTREE

Comment:

Index_comment:

1 row in set (0.00 sec)

ok,index_name 索引已被删除,现在联合username和pinyin创建索引如下:

-- 创建新索引多列组成,index_pinyin为复合索引名称

mysql> create index index_pinyin on user(username,pinyin);

Query OK, 0 rows affected (0.02 sec)

Records: 0 Duplicates: 0 Warnings: 0

-- 这里省略主键索引

mysql> show index from user \G;

*************************** 2. row ***************************

Table: user

Non_unique: 1

Key_name: index_pinyin 相同的索引名称

Seq_in_index: 1 显示列的顺序

Column_name: username

Collation: A

Cardinality: 7

Sub_part: NULL

Packed: NULL

Null:

Index_type: BTREE

Comment:

Index_comment:

*************************** 3. row ***************************

Table: user

Non_unique: 1

Key_name: index_pinyin 相同的索引名称

Seq_in_index: 2 显示列的顺序

Column_name: pinyin

Collation: A

Cardinality: 7

Sub_part: NULL

Packed: NULL

Null: YES

Index_type: BTREE

Comment:

Index_comment:

3 rows in set (0.00 sec)

像这样由两个以上组成的索引称为复合索引,由于是复合索引因此索引的名称都相同,注意Seq_in_index代表索引字段的顺序,前面我们说过在查询条件中使用了复合索引的第一个字段(这里指username),索引才会被使用。因此,在复合索引中索引列的顺序至关重要。

唯一索引

创建唯一索引必须指定关键字UNIQUE,唯一索引和单列索引类似,主要的区别在于,唯一索引限制列的值必须唯一,但允许有空值。对于多个字段,唯一索引规定列值的组合必须唯一。如创建username为唯一索引,那么username的值是不可以重复的,

-- 创建唯一索引

CREATE UNIQUE INDEX index_name ON tbl_name(index_col_name[,...]);

-- 添加(通过修改表结构)

ALTER TABLE tbl_name ADD UNIQUE INDEX index_name ON (index_col_name[,...]);

-- 创建表时直接指定

CREATE TABLE `table` (

`id` int(11) NOT NULL AUTO_INCREMENT ,

`name` varchar(32) NOT NULL ,

...... -- 其他字段

PRIMARY KEY (`id`),

UNIQUE indexName (name(32))

);

下面为user表的username字段创建唯一索引:

-- 仅为演示

create unique index idx_name on user(username);

事实上这里讲username设置为唯一索引是不合理的,毕竟用户可能存在相同username,因此在实际生产环节中username是不应该设置为唯一索引的。否则当有相同的名称插入时,数据库表将会报错。

主键索引

主键索引也称丛生索引,是一种特殊的唯一索引,不允许有空值。创建主键索引语法如下:

ALTER TABLE tbl_name ADD PRIMARY KEY(index_col_name);

一般情况下在创建表时,指明了主键时,主键索引就已自动创建了,因此无需我们手动创建。

-- 创建表时直接指定

CREATE TABLE `table` (

`id` int(11) NOT NULL AUTO_INCREMENT ,

...... -- 其他字段

PRIMARY KEY (`id`), -- 主键索引

);

索引的设计

where子句中的列可能最适合做为索引

不要尝试为性别或者有无这类字段等建立索引(因为类似性别的列,一般只含有“0”和“1”,无论搜索结果如何都会大约得出一半的数据)

如果创建复合索引,要遵守最左前缀法则。即查询从索引的最左前列开始,并且不跳过索引中的列

不要过度使用索引。每一次的更新,删除,插入都会维护该表的索引,更多的索引意味着占用更多的空间

使用InnoDB存储引擎时,记录(行)默认会按照一定的顺序存储,如果已定义主键,则按照主键顺序存储,由于普通索引都会保存主键的键值,因此主键应尽可能的选择较短的数据类型,以便节省存储空间

不要尝试在索引列上使用函数。