? 为什么要创建索引?这是因为,创建索引可以大大提高系统的查询性能。如果不使用索引,查询时从第一行开始查询。如果使用了索引,所以就可以更加快速的找到希望的数据。
? 也许有人要问:增加索引有如此多的优点,为什么不对表中的每一列创建一个索引呢?这种想法固然有其合理性,然而也有其片面性。虽然,索引有许多优点,但是,为表中的每一个列都增加索引,是非常不明智的。这是因为,增加索引也有许多不利的一个方面:
? 索引是建立在数据库表中的某些列的上面。因此,在创建索引的时候,应该仔细考虑在哪些列上可以创建索引,在哪些列上不能创建索引:
? 同样,对于有些列不应该创建索引。一般来说,不应该创建索引的这些列具有下述特点:
就是给一个列添加索引。
? 给表中大于等于两个列添加索引。但是需要满足最左前缀。
? 建立索引可以在建立表时直接指定索引,也可以后期添加索引。且要注意逐渐约束具有自动带有主键索引,唯一约束自动带有唯一索引。在MySQL中,对索引的查看和删除操作是所有索引类型通用的。
? 这是最基本的索引,他没有任何限制MyISAM中默认的BTREE类型的索引,也是我们大多数情况下用到的索引。
CREATE INDEX index_name ON table_name (column(length)) ALTER TABLE table_name ADD INDEX index_name (column(length)) CREATE TABLE table_name (id int not null auto_increment,title varchar(30),PRIMARY KEY(id),INDEX index_name(title(5))) show index from test; create index normal_index on test(title); # 查看执行计划后,直观感受查询时间 explain select * from test where title=‘正负零 0‘;
SHOW INDEX FROM [table_name]; SHOW KEYS FROM [table_name]; # 旨在MySQL中可以使用keys关键字
DROP INDEX index_name ON table_name; ALTER TABLE table_name DROP INDEX index_name; ALTER TABLE table_name DROP PRIMARY KEY;
? 与普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值(注意和主键不同)。如果是组合索引,则列值的组合必须唯一,创建方法和普通索引类
CREATE UNIQUE INDEX index_name ON table_name (column(length)) ALTER TABLE table_name ADD UNIQUE INDEX index_name (column(length)) CREATE TABLE table_name (id int not null auto_increment,title varchar(30),PRIMARY KEY(id),UNIQUE INDEX index_name(title(5))) create unique index unique_index on tescher(name); explain select * from teacher where name=‘老师3‘; drop index unique_index on teacher;
? MySQL从3.23.23版开始支持全文索引和全文检索,FULLTEXT索引在MySQL5.6之前尽可用与MyISAM表,在MySQL5.7后InnoDB也支持;他们可以从CHAR、VARCHAR或TEXT列中作为CREATE TABLE语句中的一部分被创建,或是随后使用ALTER TABLE或CREATE INDEX被添加。 ? 对于较大的数据集,将你的资料输入一个没有FULLTEXT索引的表中,然后创建索引,其速度比把资料输入现有FULLTEXT索引的速度更为快。不过切记对于大容量的数据表,生成全文索引是一个非常消耗时间非常消耗硬盘空间的做法。 ? 全文索引对中文支持不好,如果搜索中文就只能按照最左对照进行搜索,如果是英文就可以匹配中间。
CREATE FULLTEXT INDEX index_name ON table_name(column(length)) ALTER TABLE table_name ADD FULLTEXT index_name(column); CREATE TABLE table_name(id int not null auto_increment,title varchar(30),PRIMARY KEY(id),FULLTEXT index_name(title))
alter table teacher add column(address varchar(200)); update teacher set address=‘北京海淀‘; create fulltext index full_index3 on teacher(name,address); explain select * from teacher where match(address) against(‘北京‘); select * from student where match(address) against(‘bei‘ in NATURAL LANGUAGE mode); drop index full_index3 on teacher;
update teacher et address=‘山西晋城‘ where id=2; update teacher set address=‘山西晋中‘ where id=3; create fulltext index full_index_address on teacher(address); show index from teacher; select * from teacher; # 北京昌平可以查询到,但是北京无法查询到 explain select * from teacher where match(address) against(‘山西晋城‘ in natural language mode);
+ 一定要有(不含有噶关键词的数据条均被忽略)。 - 不可以有(排除指定关键词,含有该关键词的均被忽略) > 提高该条匹配数据的权重值 < 降低该条匹配数据的权重值 ~ 将其相关性由正装复,表示拥有该字会降低相关性(但不像-将之排除),只是排在较后面权重值降低。 * 万用字,不想其他愈发方子前面,这个要接在字符串后面。 "" 用双引号将一段句子抱起来表示要完全相符,不可拆字 # 查询山西*可以,但是*晋城不可以 explain select * from teacher where match(address) against(‘山西*‘ in boolean mode);
update teacher set address=‘oracle beijing changping‘ where id=1; update teacher set address=‘haidian fengtai beijing‘ where id=2; update teacher set address=‘oracle is database‘ where id=3; # 只能查询两行 explain select * from teacher where match(address) against(‘beijing changping‘ in natural language mode); # 查询到三行,因为oracle出现在beijing changping同行,查询时认为oracle和beijing changping有关,所以按照oracle进行查询 explain select * from teacher where match(address) against(‘beijing changing‘ with query EXPANSION);
由于中文是么有空格的,MySQL从5.7.6开始内置ngram中文分词插件。可以设置整个中文按照指定大小进行拆词。
ngram_token_size=2
create table ft ( id int primary key auto_increment, name varchar(20), address varchar(200) ); insert into ft values(1, ‘张三‘, ‘北京市昌平区建材城85号院‘); insert into ft values(2, ‘李四‘, ‘上海市虹桥机场‘); insert into ft values(3, ‘王五‘, ‘河北省保定市‘); insert into ft values(4, ‘赵六‘, ‘中华人民共和国北京市海淀区‘);
create fulltext index index3 on ft(address) with parse ngram;
show variables like ‘%onnodb_ft_aux_table%‘; set global innodb_ft_aux_table=‘optimization/ft‘;
select * from information_schema.INNODB_FT_INDEX_CACHE;
mysql explain select * from ft where MATCH(address) AGAINST(‘北京123市‘);
? 组合索引是创建索引时至少有两个列添加索引。创建了组合索引时实际上是创建了多个索引。所以在联合索引时把最常用的列放在最左边。
show index from teacher; create index mul_index on teacher(name, address); # 使用索引, type=ref explain select * from teacher where name=‘老师1‘; # 没有使用索引, type=index explain select * from teacher where address=‘oracle is a database‘; # 使用索引,type=ref explain select * from teacher name=‘老师1‘ and address=‘o‘;
CREATE INDEX index_name ON table_name(column_list);
? 上面都在说使用索引的好处,但过多的使用索引将会造成滥用。因此索引也会有它的缺点。虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE次数大于查询次数时,放弃索引。因此更新表时,MySQL不仅要保存数据,还要保存一下索引文件。建立索引会占用磁盘空间的索引文件。一般情况这个问题不太眼中,但如果你在一个大表上创建了多种组合索引,索引文件会膨胀很快。索引知识提高效率的一个因素,如果你的MySQL有大数据量的表,就需要花时间研究建立最优秀的索引,或优化查询语句。
CREATE INDEX index_name ON table_name(column(length));
explain select * from teahcer where address like ‘%oracle%‘;
alter table teacher add column(age int(3)); alter table teacher add column(weight int(3)); select * from teacher; update teacher set age=10,weight=90 where id=1; update teacher set age=20,weight=100 where id=2; update teacher set age=30,weight=100 where id=3; create index age_index on teacher(age); create index weight_index on teacher(weight); explain select * from teacher where age between 10 and 20 and weight between 90 and 100;
explain select * from teacher where name=20;
? 最后总结一下,MySQL只对以下操作才是用索引:<,<=,=,>=,between,in以及某些时候的like(不以通配符%或_开头的情形)。理论上每张表里面最多可创建16个索引,不过除非是数据量真的很多,否则过多的使用索引也不是那么好玩的。
explain select * from teacher where address != ‘aa‘;
select id from t where num = 10 or num-20; 可以这样查询 select id from t where num=10; union all select id from t where num = 20;
select id from t1 where num in(select id from t2 where id > 10); 此时外层查询会全表扫描,不适用索引。可以修改为: SQL select id from t1, (select id from t1 where id > 10) t2 where t1.id = t2.id; 此时索引被使用,可以明显提升查询效率。
select id from t where name like ‘%abc%‘;
模糊查询如果是必要条件时,可以使用select id from t where name like ‘abc%‘来使用模糊查询,此时索引将被使用。如果头匹配是必要逻辑,建议使用全文搜索引擎(Elasticsearch、Lucene、Solr等)。
select id from t where num/2=100; 应改为 select id from t where num = 100*2;
select id from t where substring(name, 1, 3)=‘abc‘ name以abc开头的id 应改为 select id from t where name like ‘abc%‘;
select col1,col2 into # from t where 1=0; 这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样: create table #t(...)
select num from a where num in (select num from b) 用下面的语句替换 select num from a where exists(select 1 from b where num = a.num)
不使用*、尽量不适用union,union all等关键字,尽量不适用or关键字、尽量使用等值判断。
表连接建议不超过5个。如果超过5个,则考虑表格的设计。(互联网应用中).
表连接方式使用外联由于内联。 外连接有基础数据存在。如:A left join B,基础数据是A。 A inner join B,没有基础数据的,先使用笛卡尔积完成全连接,再根据连接条件得到内连接结果集。
大数据量级的表格做分页查询时,如果页码数量过大,则使用子查询配合完成分页逻辑。
select * from table limit 1000000, 10; select * from table where id in (select pk from table limit 1000000, 10);
原文:https://www.cnblogs.com/zhangyafei/p/13903681.html