MySQL MySQL [eleven] create index create index

MySQL to create the index

 

Creating an index

Copy the code
# Method One: When you create a table 
      CREATE TABLE table name ( 
                field name 1 data type [integrity constraints ...], 
                field name 2 Data Type [integrity constraints ...], 
                [UNIQUE | FULLTEXT | the SPATIAL] INDEX | KEY 
                [index name] (field [(length)] [the ASC | DESC]) 
                ); 


# method two: CREATE created on existing tables indexed 
        CREATE [UNIQUE | FULLTEXT | SPATIAL] iNDEX index name 
                     oN table name (field name [( length)] [ASC | DESC]); 


# method three: ALTER tABLE create an index on an existing table 
        ALTER tABLE table ADD [UNIQUE | FULLTEXT | SPATIAL] iNDEX 
                             index name (field name [(length)] [ASC | DESC]); 
                             
# delete the index: DROP iNDEX index name ON table name;
Copy the code
#方式一
create table t1(
    id int,
    name char,
    age int,
    sex enum('male','female'),
    unique key uni_id(id),
    index ix_name(name) #index没有key
);
create table t1(
    id int,
    name char,
    age int,
    sex enum('male','female'),
    unique key uni_id(id),
    index(name) #index没有key
);


#方式二
create index ix_age on t1(age);


#方式三
alter table t1 add index ix_sex(sex);
alter table t1 add index(sex);

#查看
mysql> show create table t1;
| t1    | CREATE TABLE `t1` (
  `id` int(11) DEFAULT NULL,
  `name` char(1) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `sex` enum('male','female') DEFAULT NULL,
  UNIQUE KEY `uni_id` (`id`),
  KEY `ix_name` (`name`),
  KEY `ix_age` (`age`),
  KEY `ix_sex` (`sex`)
) ENGINEThe DEFAULT = the InnoDB the CHARSET = latin1 

example
example

Testing Index

data preparation

# 1. Preparation Table 
Create Table S1 ( 
ID int, 
name VARCHAR ( 20 is ), 
Gender char ( . 6 ), 
In Email VARCHAR ( 50 ) 
); 

# 2. Create a stored procedure, inserted in batches recording 
DELIMITER $$ # statement stored procedure end symbol $$ 
Create Procedure auto_insert1 () 
the BEGIN 
    DECLARE default I int . 1 ;
     the while (I <3,000,000 ) do 
        INSERT INTO S1 values (I, ' EVA ' , ' FEMALE ' , the concat ( ' EVA ' , I, ' @oldboy ')); 
        SET I = I +. 1 ; 
    End the while ; 
the END $$ # $$ end 
DELIMITER; # restated semicolon end symbol 

# 3. See stored procedure 
Show Create Procedure auto_insert1 \ G 

# 4. call a stored procedure 
call auto_insert1 ();
View Code

Test Query speed in the premise of no index

# No index: mysql do not know in the end whether there is a record id equal to 333333333, and only the data table from start to finish scanning again, this time the number of disk blocks on how much IO operations, the query is slow 
mysql> S1 * from WHERE ID SELECT = 333333333; 
Empty SET (0.33 sec)

Under the premise of large amounts of data that already exists in the table, to index a field segment, the establishment can be slow

After indexing is complete, when the field is to the query, the query speed increase significantly

PS:

1. mysql go index table according to the principle of the search tree b + id equal to quickly search the record does not exist 333333333, the IO significantly reduced, thus significantly faster

2. We can find the data directory to the mysql table, you can see more hard disk space occupied

3. Note that, as FIG.

Summary :

Copy the code
# 1 field must be created for the search index, such as select * from s1 where id = 333 ; id you need to add an index 

case # 2 has a lot of data in the table, indexing will be very slow. and take up hard disk space, construction accelerated after the query 
, such as on s1 (id) create index idx ; all data will scan the table, then the data item id, index structure is created, stored in the hard disk of the table. 
Once created, then the query will be much faster. 

# 3 Note that: the index innodb table will be stored in s1.ibd file, and the index myisam table will have separate index file table1.MYI 

MySAM index and data files are separate index file is saved only address data records. In innodb, the table data file itself is in accordance with B + Tree (BTree i.e. Balance True) an index structure of the tissue, this tree leaf node data field holds a complete data record. The key is the primary key index of the data table, so innodb table data file itself is the main index. 
Because inndob data files in accordance with the primary key aggregation, so innodb claim table must have a primary key (Myisam can not), if not explicitly defined, mysql system will automatically select a column as the primary key uniquely identifies a data record, if there is no such columns, mysql innodb table will automatically generate a hidden field as the primary key, the length of this field is 6 bytes long integer type.
Copy the code

If you can hit the correct index

Index Misses

Not that we create the index will certainly speed up queries, if you want to use the index to achieve the desired effect of improving the speed of queries, when we add an index, subject to the following issues

Scope of the problem, or that conditions are not clear

These symbols or keywords appear conditions: >,> =, <, <=, =, and ... the BETWEEN ...,! Like,

Number greater than, less than the number

not equal to! =

between ...and...

like

Discrimination issues

To select a high-sensitive column as an index, the discrimination equation is count (distinct col) / count (*), indicates the ratio of the field will not be repeated, the ratio of the number of records the greater the fewer we scanned, discrimination is unique key 1, and some states, gender field is probably 0, then one might ask in the face of big data discrimination, this ratio you have any experience? Different usage scenarios, this value is difficult to determine, in general we need to join fields are required to be 0.1 or more, i.e., an average of 10 scans recorded

mysql> desc s1;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id     | int(11)     | YES  | MUL | NULL    |       |
| name   | varchar(20) | YES  |     | NULL    |       |
| gender | char(5)     | YES  |     | NULL    |       |
| email  | varchar(50) | YES  | MUL | NULL    |       |
+--------+-------------+------+-----+---------+-------+
rows in set (0.00 sec)

mysql> drop index a on s1;
Query OK, 0 rows affected (0.20 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> drop index d on s1;
Query OK, 0 rows affected (0.18 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc s1;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id     | int(11)     | YES  |     | NULL    |       |
| name   | varchar(20) | YES  |     | NULL    |       |
| gender | char(5)     | YES  |     | NULL    |       |
| email  | varchar(50) | YES  |     | NULL    |       |
+--------+-------------+------+-----+---------+-------+
rows in set (0.00 sec)

先把表中的索引都删除,让我们专心研究区分度的问题
先把表中的索引都删除,让我们专心研究区分度的问题

我们编写存储过程为表s1批量添加记录,name字段的值均为egon,也就是说name这个字段的区分度很低(gender字段也是一样的,我们稍后再搭理它)

回忆b+树的结构,查询的速度与树的高度成反比,要想将树的高低控制的很低,需要保证:在某一层内数据项均是按照从左到右,从小到大的顺序依次排开,即左1<左2<左3<...

而对于区分度低的字段,无法找到大小关系,因为值都是相等的,毫无疑问,还想要用b+树存放这些等值的数据,只能增加树的高度,字段的区分度越低,则树的高度越高。极端的情况,索引字段的值都一样,那么b+树几乎成了一根棍。本例中就是这种极端的情况,name字段所有的值均为'egon'

#现在我们得出一个结论:为区分度低的字段建立索引,索引树的高度会很高,然而这具体会带来什么影响呢???

#1:如果条件是name='xxxx',那么肯定是可以第一时间判断出'xxxx'是不在索引树中的(因为树中所有的值均为'egon’),所以查询速度很快

#2:如果条件正好是name='egon',查询时,我们永远无

分析原因
分析原因

索引列不能在条件中参与计算

索引列不能在条件中参与计算,保持列“干净”,比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很简单,b+树中存的都是数据表中的字段值,但进行检索时,需要把所有元素都应用函数才能比较,显然成本太大。所以语句应该写成create_time = unix_timestamp(’2014-05-29’)

 

 and/or

Copy the code
#1、and与or的逻辑
    条件1 and 条件2:所有条件都成立才算成立,但凡要有一个条件不成立则最终结果不成立
    条件1 or 条件2:只要有一个条件成立则最终结果就成立

#2、and的工作原理
    条件:
        a = 10 and b = 'xxx' and c > 3 and d =4
    索引:
        制作联合索引(d,a,b,c)
    工作原理:
        对于连续多个and:mysql会按照联合索引,从左到右的顺序找一个区分度高的索引字段(这样便可以快速锁定很小的范围),加速查询,即按照d—>a->b->c的顺序

#3、or的工作原理
    条件:
        a = 10 or b = 'xxx' or c > 3 or d =4
    索引:
        制作联合索引(d,a,b,c)
        
    工作原理:
        对于连续多个or:mysql会按照条件的顺序,从左到右依次判断,即a->b->c->d
Copy the code

在左边条件成立但是索引字段的区分度低的情况下(name与gender均属于这种情况),会依次往右找到一个区分度高的索引字段,加速查询

经过分析,在条件为name='egon' and gender='male' and id>333 and email='xxx'的情况下,我们完全没必要为前三个条件的字段加索引,因为只能用上email字段的索引,前三个字段的索引反而会降低我们的查询效率

最左前缀匹配原则

非常重要的原则,对于组合索引mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配(指的是范围大了,有索引速度也慢),比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。

其他情况

Copy the code
使用函数
    select * from tb1 where reverse(email) = 'egon';
            
- 类型不一致
    如果列是字符串类型,传入条件是必须用引号引起来,不然...
    select * from tb1 where email = 999;
    
#排序条件为索引,则select字段必须也是索引字段,否则无法命中
- order by
    select name from s1 order by email desc;
    当根据索引排序时候,select查询的字段如果不是索引,则速度仍然很慢
    select email from s1 order by email desc;
    特别的:如果对主键排序,则还是速度很快:
        select * from tb1 order by nid desc;
 
- 组合索引最左前缀
    如果组合索引为:(name,email)
    name and email       -- 命中索引
    name                 -- 命中索引
    email                -- 未命中索引


- count(1)或count(列)代替count(*)在mysql中没有差别了

- create index xxxx  on tb(title(19)) #text类型,必须制定长度
Copy the code

其他注意事项

Copy the code
- 避免使用select *
- 使用count(*)
- 创建表时尽量使用 char 代替 varchar
- 表的字段顺序固定长度的字段优先
- 组合索引代替多个单列索引(由于mysql中每次只能使用一个索引,所以经常使用多个条件查询时更适合使用组合索引)
- 尽量使用短索引
- 使用连接(JOIN)来代替子查询(Sub-Queries)
- 连表时注意条件类型需一致
- 索引散列值(重复少)不适合建索引,例:性别不适合
Copy the code

联合索引

联合索引

联合索引是指对表上的多个列合起来做一个索引。联合索引的创建方法与单个索引的创建方法一样,不同之处仅在于有多个索引列,如:

Copy the code
 
mysql> create table t(
    -> a int,
    -> b int,
    -> primary key(a),
    -> key idx_a_b(a,b)
    -> );
Query OK, 0 rows affected (0.11 sec)
 
Copy the code

覆盖索引

InnoDB存储引擎支持覆盖索引(covering index,或称索引覆盖),即从辅助索引中就可以得到查询记录,而不需要查询聚集索引中的记录。

覆盖索引 查一个数据不需要回表
    select name from 表 where age = 20   不是覆盖索引
    select age from 表 where age =20  是覆盖索引
    select count(age) from 表 where age =20  是覆盖索引

合并索引

Copy the code
 
当我们为单独的一列创建索引的时候
    如果条件是这一列,且使用正确就可以命中索引
当我们为两列分别创建单独的索引的时候
    如果这两列都是条件,那么可能只能命中期中一个条件
    如果这两列都是条件,那么可能会命中两个索引  - 合并索引
我们为多列直接创建联合所以
    条件命中联合索引
 
Copy the code

索引总结:

Copy the code
 
1.条件一定是建立了索引的字段,如果条件使用的字段根本就没有创建索引,那么索引不生效
2.如果条件是一个范围,随着范围的值逐渐增大,那么索引能发挥的作用也越小
3.如果使用like进行模糊查询,那么使用a%的形式能命中索引,%a形式不能命中索引
4.尽量选择区分度高的字段作为索引列
5.索引列不能在条件中参与计算,也不能使用函数
6.在多个条件以and相连的时候,会优点选择区分度高的索引列来进行查询
  在多个条件以or相连的时候,就是从左到右依次判断
7.制作联合索引
    1.最左前缀原则 a,b,c,d 条件是a的能命中索引,条件是a,b能命中索引,a,b,c能命中,a,c.... 只要没有a就不能命中索引
        如果在联合查询中,总是涉及到同一个字段,那么就在建立联合索引的时候将这个字段放在最左侧
    2.联合索引 如果按照定义顺序,从左到右遇到的第一个在条件中以范围为条件的字段,索引失效
        尽量将带着范围查询的字段,定义在联合索引的最后面
    drop index
    如果我们查询的条件总是多个列合在一起查,那么就建立联合索引
        create index ind_mix on s1(id,email)

        select * from s1 where id = 1000000    命中索引
        select * from s1 where email = 'eva1000000@oldboy'  未命中索引
        但凡是创建了联合索引,那么在查询的时候,再创建顺序中从左到右的第一列必须出现在条件中
        select count(*) from s1 where id = 1000000 and email = 'eva10%';  命中索引

        select count(*) from s1 where id = 1000000 and email like 'eva10%'; 可以命中索引
        范围 :
        select * from s1 where id >3000 and email = 'eva300000@oldboy';  不能命中索引
8.条件中涉及的字段的值必须和定义表中字段的数据类型一致,否则不能命中索引
 
Copy the code

执行计划

执行计划
看看mysql准备怎么执行这条语句 可以看到是否命中索引,计划能命中哪些,实际命中了哪些,执行的顺序,是否发生了索引合并,覆盖索引
explain select * from s1;

创建索引

Copy the code
# Method One: When you create a table 
      CREATE TABLE table name ( 
                field name 1 data type [integrity constraints ...], 
                field name 2 Data Type [integrity constraints ...], 
                [UNIQUE | FULLTEXT | the SPATIAL] INDEX | KEY 
                [index name] (field [(length)] [the ASC | DESC]) 
                ); 


# method two: CREATE created on existing tables indexed 
        CREATE [UNIQUE | FULLTEXT | SPATIAL] iNDEX index name 
                     oN table name (field name [( length)] [ASC | DESC]); 


# method three: ALTER tABLE create an index on an existing table 
        ALTER tABLE table ADD [UNIQUE | FULLTEXT | SPATIAL] iNDEX 
                             index name (field name [(length)] [ASC | DESC]); 
                             
# delete the index: DROP iNDEX index name ON table name;
Copy the code

Guess you like

Origin www.cnblogs.com/youxiu123/p/11493052.html