Mysql:
建表语句?
CREATE TABLE grade (
no int(11) NOT NULL,
id int(11) NOT NULL,
kemu varchar(255) DEFAULT NULL,
score int(11) DEFAULT NULL,
PRIMARY KEY (no)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE student (
id int(11) NOT NULL,
name varchar(255) DEFAULT NULL,
age int(11) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
插入语句?
INSERT INTO student.grade (no, id, kemu, score) VALUES (1, 1001, ‘语文’, 85);
INSERT INTO student.grade (no, id, kemu, score) VALUES (2, 1001, ‘数学’, 86);
INSERT INTO student.grade (no, id, kemu, score) VALUES (3, 1002, ‘英语’, 98);
INSERT INTO student.grade (no, id, kemu, score) VALUES (4, 1002, ‘语文’, 94);
INSERT INTO student.grade (no, id, kemu, score) VALUES (5, 1002, ‘数学’, 98);
INSERT INTO student.grade (no, id, kemu, score) VALUES (6, 1003, ‘数学’, 56);
INSERT INTO student.grade (no, id, kemu, score) VALUES (7, 1003, ‘语文’, 69);
INSERT INTO student.grade (no, id, kemu, score) VALUES (8, 1003, ‘英语’, 68);
INSERT INTO student.grade (no, id, kemu, score) VALUES (9, 1004, ‘英语’, 99);
INSERT INTO student.grade (no, id, kemu, score) VALUES (10, 1004, ‘数学’, 97);
INSERT INTO student.student (id, name, age) VALUES (1001, ‘张三’, 18);
INSERT INTO student.student (id, name, age) VALUES (1002, ‘张四’, 19);
INSERT INTO student.student (id, name, age) VALUES (1003, ‘张五’, 20);
INSERT INTO student.student (id, name, age) VALUES (1004, ‘张六’, 19);
更新语句?
UPDATe student.student SET id=‘1001’, name=‘张三’, age=‘18’ WHERe (id=‘1001’);
#习题
#1.查询所有学生的数学成绩,显示学生姓名 name, 分数, 由高到低
select t1.name,t2.score ,t2.kemu from student t1 INNER JOIN grade t2 where t1.id = t2.id and t2.kemu = “数学” ORDER BY score desc;
#2.统计每个学生的总成绩,显示字段:姓名,总成绩
select t1.name , sum(t2.score) from student t1 INNER JOIN grade t2 WHERe t1.id = t2.id group BY t1.name;
#3.统计每个学生的总成绩(由于学生可能有重复名字),显示字段:学生 id,姓名,总成绩
select a.id , a.name ,c.sum_score from student a INNER JOIN ( select b.id,SUM(b.score) as sum_score from grade b group by id ) c where a.id = c.id ORDER BY c.sum_score desc;
#4.列出各门课程成绩最好的学生, 要求显示字段: 学号,姓名,科目,成绩
select t3.id,t3.name, t2.kemu ,t2.max_score from student t3 inner join ( select t1.id , t1.kemu,max(t1.score) as max_score from grade t1 GROUP BY t1.kemu) t2 where t3.id = t2.id;
#5.列出各门课程成绩最好的 2 位学生, 要求显示字段: 学号,姓名, 科目,成绩
select t1.id,t2.name,t1.kemu,t1.score from grade t1 inner JOIN student t2 where (select count(*) from grade t3 where t1.kemu = t3.kemu and t3.score > t1.score ) < 2 and t2.id = t1.id ORDER BY t1.kemu,t1.score desc;
#1.计算每个人的平均成绩, 要求显示字段: 学号,姓名,平均成绩
select t1.id , t1.name, avg(t2.score) as avg_score from student t1 inner JOIN grade t2 where t1.id = t2.id GROUP BY t1.name;
#2.计算每个人的成绩,总分数,平均分,要求显示:学号,姓名,语文,数学,英语,总分,平均分
select t1.id as 学号,t1.name as 姓名,
sum(case when t2.kemu = ‘语文’ then score else 0 end) as 语文,
sum(case when t2.kemu = ‘数学’ then score else 0 end) as 数学,
sum(case when t2.kemu = ‘英语’ then score else 0 end) as 英语,
sum(t2.score) as 总分,
sum(t2.score)/count(t2.score) as 平均分
from student t1 inner JOIN grade t2 where t1.id = t2.id GROUP BY t2.id
#3.列出各门课程的平均成绩,要求显示字段:课程,平均成绩
select kemu ,avg(score) from grade GROUP BY kemu ;
#4.列出数学成绩的排名, 要求显示字段:学号,姓名,成绩,排名
select t1.id as 学号,t2.name as 姓名, t1.score as 成绩 , @paiming := @paiming+1 as 排名 from
(select g.id,g.score ,g.kemu from grade g) as t1 , student as t2 ,(select @paiming := 0) as r WHERe t1.id = t2.id and t1.kemu = ‘数学’ ORDER BY t1.score desc;
#1.列出数学成绩前 3 名的学生(要求显示字段:学号,姓名, 科目,成绩)
select t1.id ,t2.name , t1.kemu, t1.score from grade t1 INNER JOIN student t2 where t1.id = t2.id and t1.kemu = ‘数学’ order BY t1.score desc LIMIT 3;
#2.查询数学成绩第 2 和第 3 名的学生
select t1.id ,t2.name , t1.kemu, t1.score from grade t1 INNER JOIN student t2 where t1.id = t2.id and t1.kemu = ‘数学’ order BY t1.score desc LIMIT 1,2;
#3.查询第 3 名到后面所有的学生数学成绩
select t1.id ,t2.name , t1.kemu, t1.score from grade t1 INNER JOIN student t2 where t1.id = t2.id and t1.kemu = ‘数学’ order BY t1.score desc LIMIT 3,10000000;
#4.统计英语课程少于 80 分的,显示 学号 id, 姓名,科目,分数
select t1.id,t2.name,t1.kemu,t1.score from grade t1 INNER JOIN student t2 where t1.id = t2.id and t1.kemu = “英语” and t1.score < 80;
#5.用一条 SQL 语句查询 xuesheng 表每门课都大于 80 分的学生姓名
select t1.id,t2.name,t1.kemu,t1.score from grade t1 INNER JOIN student t2 where t1.id = t2.id and t1.score > 80;
添加字段?
alter table student add sex varchar(64) DEFAULT NULL;
查看数据表结构或字段?
desc table_name;
show columns from tq_comp_guaranteedetails;
查看生成表的DDL?
show create table table_name;
删除表?
drop table table_name
删除字段?
alter table table_name drop column column_name;
清空表?
truncate table table_name
sql 设置UTF8?
SET NAMES ‘utf8’;
枚举状态?
select *,if(car_brand_status < 1 ,“fail”,“sucess”) as status from dave_car_brand;
枚举值替换?
SELECt
CASE t1.source
WHEN 1 THEN
“安硕”
WHEN 2 THEN
“爬虫”
WHEN 3 THEN
“后台”
WHEN 4 THEN
“百度”
ELSE
‘其他’
END AS “新闻来源描述”
FROM
bond_sentiment_news_essence t1
取值,长度等于8取前4位,长度等于7取前3位?
SELECt
CASE LENGTH(car_brand_code)
WHEN 8 THEN
SUBSTr(car_brand_code, 1,4)
WHEN 7 THEN
SUBSTr(car_brand_code , 1 ,3)
ELSE “”
END AS car_brand_code
FROM
dave_car_brand;
查询电话号码第三位为8,9并以888结尾的作者的信息:
SELECt * FROM AUTHORS WHERe ( SUBSTr(telephone, 3, 1) = ‘8’ OR SUBSTr(telephone, 3, 1) = ‘9’ ) AND SUBSTr(telephone.length (telephone) - 2,3) = ‘888’
给表某一字段创建索引?
create index IDX_STUDENT_AGE ON student(age);
create index IDX_STUDENT_NAME ON student(name);
去重字段?
distinct
通过正则表达式查询?
select * from student where age REGEXP(‘[1-9]’)
查询年份月份?
select year(create_time),MONTH(create_time) from abs_mortgage_status;
主键和唯一索引的区别?
相同点:他们都属于完整性约束。
不同点:
(1)唯一性所在的列允许空值,但主键所在的列不允许空值。
(2)唯一性约束可以放在一列或多列上,但不能在主键列上。
(3)建立主键的目的是让外建来应用。
(4)一个表最多只有一个主键,但可以有很多唯一键。
什么是基本表?什么是视图?
基本表是本身独立存在的表,在sql中一个关系对应一个表.视图是从一个或几个基本表中导出的表。视图本身不独立存储在数据库中,是一个虚表。
Mysql 有哪些引擎?有什么区别?
主要 MyISAM 与 InnoDB 两个引擎
区别:InnoDB 支持事务,MyISAM 不支持;
InnoDB支持外键,MyISAM 不支持;
MyISAM是默认引擎,InooDB需要指定;
InnoDB 不支持FULLTEXT 类型的索引;
InnoDB不保存表的行数,如 select count() from table 时,需要扫描整张表来计算多少行,MyISAM 只要简单读出保存好的行数,当conut() 语句包含where 条件时也需要扫描整张表进行计算。
对于自增长的字段,InnoDB 必须包含只有改字段的索引,MyISAM会和其他字段一起建立联合索引;
清空表时,InnoDB 一行一行删除,效率慢,MyISAM 则会重建表;
InnoDB 支持行锁;
数据库常用命令?
创建数据库:create database name;
进入数据库:use databasebane;
直接删除数据库不提醒:drop database name;
显示表:show tables;
查看表结构:describe/desc tablename;
去除重复字段:select distinct …
显示mysql当前版本;select version();
显示当前日期:select current_date()
修改数据库密码:update user set passd = ‘’ where user = ‘’;
索引的优点和缺点?
优点:加快数据检索速度;
创建唯一索引,保证数据库每一行的唯一性;
加速表与表之间的链接;
减少查询中分组和排序的时间;
缺点:
创建索引和维护索引需要时间,维护成本增加;
索引需要占用物理空间;
主键和外键的区别?
主键是确认一条记录的唯一标识,只有一个;
外键用于与其他表关联,可以有多个;
数据库的锁有哪几种?
读写锁,表锁,行锁
存储过程作用及怎么编写?
数据库提供两种类型的语言,是什么有什么作用?
数据库描述语言(DDL):更改数据库的结构,create,drop,alter,truncate,rename
数据库操作语言(DML):管理数据库中的数据,insert,update,delete,select
请写出内连接,左连接,右连接的关键字,并简述其作用?
LEFT JOIN:左连接,会读取左表的全部数据,即便右表没有对应的数据,左连接会从左表生产一套完整的记录,和右表匹配的记录,如果右表没有匹配记录,右侧结果集字段将为null;
RIGHT JOIN:右连接,以右表为基础。与LEFT JOIN 相反;
INNER JOIN:内连接或者等值连接,可以获取两个表中字段匹配关系的记录;
触发器的作用是什么?
相当于一个触发装置,在进行增删改查操作时可以触发需要的操作,如写入时,对行数数据校验,发生错误时回滚数据等等;
union 和 union all 的区别?
union 用于合并两个或多个select 语句的结果集。union 内部的select 语句必须拥有相同数列的列,列也必须拥有相似的数据类型;
union 对数据进行并集操作,不包括重复行,同时进行默认排序,union all 要比union 快很多,Union all 对数据进行并集操作,包括重复行,不进行排序;
Sequence 的作用是什么?举个使用sequence 的案例?
sequence 是Oracle 的序列,可以用来生成唯一数据,作为记录的主键值,在mysql 中使用自动增长 auto_increment;
Function 和 procedure 的区别?
function 是函数,procedure 是存储过程,函数可以有返回值,存储过程没有;
索引的基本原理?
索引用来快速的寻找那些局域特定值的记录。如果没有索引,一般来说执行查询时遍历整张表。
索引的原理很简单,就是把无序的数据变成有序的查询;
把创建索引的列进行排序,对排序结果生成倒排表,在倒排表内容上拼上数据地址链,在查询的时候先拿到倒排表的内容,再取出数据地址链,从而拿到具体数据;
创建索引的三种方式?
1.CREATE TABLE 时创建索引;
2.ALTTER TABLE 命令增加索引;
3.CREATE INDEX 命令创建;
#{} 和 ${} 的区别是什么?
#{}是预编译处理、是占位符,
" KaTeX parse error: Expected 'EOF', got '#' at position 30: …符。 Mybatis 在处理#̲{}时,会将 sql 中的#{…{}时, 就是把${}替换成变量的值,调用 Statement 来赋值;
#{} 的变量替换是在DBMS 中、变量替换后,#{} 对应的变量自动加上单引号
的变量替换是在
D
B
M
S
外、变量替换后,
{} 的变量替换是在 DBMS 外、变量替换后,
的变量替换是在DBMS外、变量替换后,{} 对应的变量不会加上单引号
使用#{}可以有效的防止 SQL 注入, 提高系统安全性。
Mysql 锁的类型有哪些?
基于锁的属性分类:共享锁、排他锁。
基于锁的粒度分类:行级锁(INNODB)、表级锁(INNODB、MYISAM)、页级锁(BDB引擎 )、记录锁、间 隙锁、临键锁。
基于锁的状态分类:意向共享锁、意向排它锁。
共享锁(Share Lock):共享锁又称读锁,简称S锁;当一个事务为数据加上读锁之后,其他事务只能对
该数据加读锁,而不能对 数据加写锁,直到所有的读锁释放之后其他事务才能对其进行加持写
锁。共享锁的特性主要是为了支持 并发的读取数据,读取数据的时候不支持修改,避免出现重
复读的问题。
排他锁(eXclusive Lock):排他锁又称写锁,简称X锁;当一个事务为数据加上写锁时,其他请求将不
能再为数据加任何锁,直到该 锁释放之后,其他事务才能对数据进行加锁。排他锁的目的是在
数据修改时候,不允许其他人同时修 改,也不允许其他人读取。避免了出现脏数据和脏读的问
题。
表锁 :表锁是指上锁的时候锁住的是整个表,当下一个事务访问该表的时候,必须等前一个事务释放
了锁才能 进行对表进行访问; 特点: 粒度大,加锁简单,容易冲突
行锁:
行锁是指上锁的时候锁住的是表的某一行或多行记录,其他事务访问同一张表时,只有被锁住
的记录不 能访问,其他的记录可正常访问; 特点:粒度小,加锁比表锁麻烦,不容易冲突,相
比表锁支持的并发要高;
记录锁(Record Lock):记录锁也属于行锁中的一种,只不过记录锁的范围只是表中的某一条记录,记
录锁是说事务在加锁后锁 住的只是表的某一条记录。 精准条件命中,并且命中的条件字段是唯
一索引 加了记录锁之后数据可以避免数据在查询的时候被修改的重复读问题,也避免了在修改
的事务未提交前 被其他事务读取的脏读问题
页锁:页级锁是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行
级 冲突 少,但速度慢。所以取了折衷的页级,一次锁定相邻的一组记录。 特点:开销和加锁时
间 界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般
间隙锁(Gap Lock):属于行锁中的一种,间隙锁是在事务加锁后其锁住的是表记录的某一个区间,当表
的相邻ID之间出现空 隙则会形成一个区间,遵循左开右闭原则。 范围查询并且查询未命中记
录,查询条件必须命中索引、间隙锁只会出现在REPEATABLE_READ(重复 读)的事务级别中。
触发条件:防止幻读问题,事务并发的时候,如果没有间隙锁,就会发生如下图的问题,在同一
个事务 里,A事务的两次查询出的结果会不一样。 比如表里面的数据ID 为 1,4,5,7,10 ,那么会形
成以下几个间隙区间,-n-1区间,1-4区间,7-10 区间,10-n区间 (-n代表负无穷大,n代表正
无穷大)
临建锁(Next-Key Lock):也属于行锁的一种,并且它是INNODB的行锁默认算法,总结来说它就是记录
锁和间隙锁的组合,临键锁 会把查询出来的记录锁住,同时也会把该范围查询内的所有间隙空间
也会锁住,再之它会把相邻的下一 个区间也会锁住 触发条件:范围查询并命中,查询命中了索
引。 结合记录锁和间隙锁的特性,临键锁避免了在范围查询时出现脏读、重复读、幻读问题。加
了临键锁之 后,在范围区间内数据不允许被修改和插 入。
意向共享锁:当一个事务试图对整个表进行加共享锁之前,首先需要获得这个表的意向共享锁
意向排他锁:当一个事务试图对整个表进行加排它锁之前,首先需要获得这个表的意向排它锁。
事务的基本特性和隔离级别?
事务基本特性ACID分别是:
原子性指的是一个事务中的操作要么全部成功,要么全部失败。
一致性指的是数据库总是从一个一致性的状态转换到另外一个一致性的状态。
隔离性指的是一个事务的修改在最终提交前,对其他事务是不可见的。
持久性指的是一旦事务提交,所做的修改就会永久保存到数据库中。
隔离性有4个隔离级别,分别是:
read uncommit 读未提交,可能会读到其他事务未提交的数据,也叫做脏读。
read commit 读已提交,两次读取结果不一致,叫做不可重复读。 不可重复读解决了脏读的问题,他只会读取已经提交的事务。 用户开启事务读取id=1用户,查询到age=10,再次读取发现结果=20,在同一个事务里同一个查 询读取到不同的结果叫做不可重复读。
repeatable read 可重复复读,这是mysql的默认级别,就是每次读取结果都一样,但是有可能产 生幻读。
serializable 串行,一般是不会使用的,他会给每一行读取的数据加锁,会导致大量超时和锁竞争 的问题。
脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因, 前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的。
不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中 间插入了一个事务更新的原有的数据。
幻读(Phantom Read):在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数 据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据 是它先前所没有的。
ACID 靠什么保证?
A原子性由undo log日志保证,它记录了需要回滚的日志信息,事务回滚时撤销已经执行成功的sql
C一致性由其他三大特性保证、程序代码要保证业务上的一致性
I隔离性由MVCC来保证
D持久性由内存+redo log来保证,mysql修改数据同时在内存和redo log记录这次操作,宕机的时候可 以从redo log恢复
InnoDB redo log 写盘,InnoDB 事务进入 prepare 状态。 如果前面 prepare 成功,binlog 写盘,再继续将事务日志持久化到 binlog,如果持久化成功,那么 InnoDB 事务则进入 commit 状态(在 redo log 里面写一个 commit 记录),redolog的刷盘会在系统空闲时进行
关心过业务系统里面的sql耗时吗?统计过慢查询吗?对慢 查询都怎么优化过?
首先分析语句,看看是否load了额外的数据,可能是查询了多余的行并且抛弃掉了,可能是加载 了许多结果中并不需要的列,对语句进行分析以及重写。
分析语句的执行计划,然后获得其使用索引的情况,之后修改语句或者修改索引,使得语句可以尽 可能的命中索引。
如果对语句的优化已经无法进行,可以考虑表中的数据量是否太大,如果是的话可以进行横向或者 纵向的分表。
Mysql主从同步原理?
Mysql的主从复制中主要有三个线程: master(binlog dump thread)、slave(I/O thread 、SQL thread) ,Master一条线程和Slave中的两条线程。
主节点 binlog,主从复制的基础是主库记录数据库的所有变更记录到 binlog。binlog 是数据库服 务器启动的那一刻起,保存所有修改数据库结构或内容的一个文件。
主节点 log dump 线程,当 binlog 有变动时,log dump 线程读取其内容并发送给从节点。
从节点 I/O线程接收 binlog 内容,并将其写入到 relay log 文件中。
从节点的SQL 线程读取 relay log 文件内容对数据更新进行重放,最终保证主从数据库的一致性。
注:主从节点使用 binglog 文件 + position 偏移量来定位主从同步的位置,从节点会保存其已接收到的 偏移量,如果从节点发生宕机重启,则会自动从 position 的位置发起同步。
由于mysql默认的复制方式是异步的,主库把日志发送给从库后不关心从库是否已经处理,这样会产生 一个问题就是假设主库挂了,从库处理失败了,这时候从库升为主库后,日志就丢失了。由此产生两个 概念。
全同步复制 主库写入binlog后强制同步日志到从库,所有的从库都执行完成后才返回给客户端,但是很显然这个方 式的话性能会受到严重影响。
半同步复制 和全同步不同的是,半同步复制的逻辑是这样,从库写入日志成功后返回ACK确认给主库,主库收到至 少一个从库的确认就认为写操作完成。
MyISAM 和 InnoDM 的区别?
MyISAM:
不支持事务,但是每次查询都是原子的;
支持表级锁,即每次操作是对整个表加锁;
存储表的总行数;
一个MYISAM表有三个文件:索引文件、表结构文件、数据文件;
采用非聚集索引,索引文件的数据域存储指向数据文件的指针。辅索引与主索引基本一致,但是辅索引 不用保证唯一性。
InnoDb:
支持ACID的事务,支持事务的四种隔离级别; 支持行级锁及外键约束:因此可以支持写并发; 不存储总行数;
一个InnoDb引擎存储在一个文件空间(共享表空间,表大小不受操作系统控制,一个表可能分布在多 个文件里),也有可能为多个(设置为独立表空,表大小受操作系统文件大小限制,一般为2G),受操 作系统文件大小的限制; 主键索引采用聚集索引(索引的数据域存储数据文件本身),辅索引的数据域存储主键的值;因此从辅 索引查找数据,需要先通过辅索引找到主键值,再访问辅索引;最好使用自增主键,防止插入数据时, 为维持B+树结构,文件的大调整。
简述mysql中索引类型及对数据库的性能的影响?
普通索引:允许被索引的数据列包含重复的值。
唯一索引:可以保证数据记录的唯一性。
主键:是一种特殊的唯一索引,在一张表中只能定义一个主键索引,主键用于唯一标识一条记录,使
用 关键字 PRIMARY KEY 来创建。
联合索引:索引可以覆盖多个数据列,如像INDEX(columnA, columnB)索引。 全文索引:通过建立 倒排索引 ,可以极大的提升检索效率,解决判断字段是否包含的问题,是目前搜索引 擎使用的一种关键技术。可以通过ALTER TABLE table_name ADD FULLTEXT (column);创建全文索引 索引可以极大的提高数据的查询速度。 通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。 但是会降低插入、删除、更新表的速度,因为在执行这些写操作时,还要操作索引文件 索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚 簇索引,那么需要的空间就会更大,如果非聚集索引很多,一旦聚集索引改变,那么所有非聚集索引都 会跟着变。
sql 是怎么优化的?
通过alibaba 的Druid 定位出某个慢的接口,慢查询sqll;
查看sql执行计划:explain select * from t_bond_basic_info ;
检查索引是否被引用;
1.避免开头模糊查询,会导致数据库放弃索引进行全表扫描:
SELECt * FROM t WHERe username LIKE ‘%陈%’
优化方式:尽量在字段后面使用模糊查询。如下:
SELECt * FROM t WHERe username LIKE ‘陈%’
2.尽量避免使用in 和not in,会导致引擎走全表扫描。如下:
SELECt * FROM t WHERe id IN (2,3)`
优化方式:如果是连续数值,可以用between代替。如下:
SELECt * FROM t WHERe id BETWEEN 2 AND 3
如果是子查询,可以用exists代替。如下:
– 不走索引
select * from A where A.id in (select id from B);
– 走索引
select * from A where exists (select * from B where B.id = A.id);
3. 尽量避免使用 or,会导致数据库引擎放弃索引进行全表扫描。如下:
SELECt * FROM t WHERe id = 1 OR id = 3
优化方式:可以用union代替or。如下:
SELECt * FROM t WHERe id = 1
UNIOn
SELECt * FROM t WHERe id = 3
4. 尽量避免进行null值的判断,会导致数据库引擎放弃索引进行全表扫描。如下:
SELECt * FROM t WHERe score IS NULL
优化方式:可以给字段添加默认值0,对0值进行判断。如下:
SELECt * FROM t WHERe score = 0`
5.尽量避免在where条件中等号的左侧进行表达式、函数操作,会导致数据库引擎放弃索引进行全表扫描。
可以将表达式、函数操作移动到等号右侧。如下:
– 全表扫描
SELECt * FROM T WHERe score/10 = 9
– 走索引
SELECt * FROM T WHERe score = 10*9`
6. 当数据量大时,避免使用where 1=1的条件。通常为了方便拼装查询条件,我们会默认使用该条件,数据库引擎会放弃索引进行全表扫描。如下:
SELECt username, age, sex FROM T WHERe 1=1
优化方式:用代码拼装sql时进行判断,没 where 条件就去掉 where,有where条件就加 and。
7. 查询条件不能用 <> 或者 !=
使用索引列作为条件进行查询时,需要避免使用<>或者!=等判断条件。如确实业务需要,使用到不等于符号,需要在重新评估索引建立,避免在此字段上建立索引,改由查询条件中其他索引字段代替。
8. where条件仅包含复合索引非前置列
如下:复合(联合)索引包含key_part1,key_part2,key_part3三列,但SQL语句没有包含索引前置列"key_part1",按照MySQL联合索引的最左匹配原则,不会走联合索引。
select col1 from table where key_part2=1 and key_part3=2
9. 隐式类型转换造成不使用索引
如下SQL语句由于索引对列类型为varchar,但给定的值为数值,涉及隐式类型转换,造成不能正确走索引。
select col1 from table where col_varchar=123;
10. order by 条件要与where中条件一致,否则order by不会利用索引进行排序
– 不走age索引
SELECt * FROM t order by age;
– 走age索引
SELECt * FROM t where age > 0 order by age;
对于上面的语句,数据库的处理顺序是:
第一步:根据where条件和统计信息生成执行计划,得到数据。
第二步:将得到的数据排序。当执行处理数据(order by)时,数据库会先查看第一步的执行计划,看order by 的字段是否在执行计划中利用了索引。如果是,则可以利用索引顺序而直接取得已经排好序的数据。如果不是,则重新进行排序操作。
第三步:返回排序后的数据。
当order by 中的字段出现在where条件中时,才会利用索引而不再二次排序,更准确的说,order by 中的字段在执行计划中利用了索引时,不用排序操作。
这个结论不仅对order by有效,对其他需要排序的操作也有效。比如group by 、union 、distinct等。



