MySQL基础二
MySQL基础二
Python操作MySQL
视图
存储过程
触发器
函数
其他
索引****
Python操作MySQL
pymsql是Python中操作MySQL的模块, 使用方法和MySQLdb几乎相同
安装:
pip3 install pymysql
pip3是模块管理工具, 类似apple store, 用来管理包.
使用:
执行SQL:
import pymysql # 创建连接 conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='gkl273318', db='exercise', charset='utf8') # 创建游标(通过游标去执行操作) cursor = conn.cursor() # 执行SQL, 并返回收影响行数 r = cursor.execute('insert into class(caption) values("一年一班")') print(r) # r为执行SQl受影响的行数 # ---------- 增 ----------- # 字符串拼接SQl(不可使用) inp = input('请输入班级:') sql = 'insert into class(caption) values("%s")' %inp cursor.execute(sql) # 参数传递(必须使用) inp = input('请输入班级:') cursor.execute('insert into class(caption) values(%s)', inp) # 传递多个参数 cursor.execute('insert into student(gender,class_id,sname) values(%s,%s,%s)',('男',3,'鸭蛋')) # 需以元组的形式传参 # 传递多条参数 list = [ ('女',1,'冬瓜'), ('男',2,'西瓜'), ('女',3,'北瓜') ] cursor.executemany('insert into student(gender,class_id,sname) values(%s,%s,%s)',list) # 需以元组的形式传参 # ---------- 改 ----------- cursor.execute('update student set sname=%s where sid=%s',('马大狗',1)) # ---------- 删 ----------- cursor.execute('delete from score where sid=%s', (54,)) # 提交, 不然无法保存新建或者修改的数据 conn.commit() # 关闭游标 cursor.close() # 关闭连接 conn.close()
注意: 不可使用字符串拼接SQL, 否则会造成SQL注入(SqlInject)
import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='gkl273318', db='test1', charset='utf8') cursor = conn.cursor() # 传递参数 # cursor.execute('select username,password from userinfo where username=%s and password=%s', ('charon',123)) # result = cursor.fetchone() # print(result) #字符串拼接 sql = 'select username,password from userinfo where username="%s" and password=%s' sql = sql %('charon" or 1=1 -- ', 123456) #SQL注入, 仍可获得数据 cursor.execute(sql) result = cursor.fetchone() print(result) conn.commit() cursor.close() conn.close()
获取查询数据
import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='gkl273318', db='exercise', charset='utf8') cursor = conn.cursor() # ------------ 查(不需要commit) ------------- r = cursor.execute('select * from student') print(r) # 获取所有数据 result = cursor.fetchall() print(result) # 获取第一行数据 result = cursor.fetchone() print(result) # 获取前n行数据 result = cursor.fetchmany(3) print(result) /* 注: 在fetch数据时按照顺序进行, 可以使用cursor.scroll(num,mode)来移动游标位置, 如: cursor.scroll(1,mode='relative') # 相对当前位置移动 cursor.scroll(2,mode='absolute') # 相对绝对位置移动 */ result = cursor.fetchmany(3) print(result) # cursor.scroll(0,mode='absolute') cursor.scroll(-1,mode='relative') result = cursor.fetchmany(2) print(result) cursor.close() conn.close()
fetch数据类型
关于默认获取的数据是元祖类型, 如果想要或者字典类型的数据:
import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='exercise', charset='utf8') # 游标设置为字典类型 cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) r = cursor.execute('select * from student') result = cursor.fetchone() conn.commit() cursor.close() conn.close()
获取新创建数据自增ID
import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='exercise', charset='utf8) cursor = conn.cursor() cursor.executemany('insert into student(gender,class_id,sname) values(%s,%s,%s)',('男',3,'鸭蛋')) conn.commit() cursor.close() conn.close() # 获取最新自增ID new_id = cursor.lastrowid print(new_id)
视图
视图是一个虚拟表(临时表), 其本质是根据SQL语句获取动态的数据集, 并为其命名. 用户使用时只需使用 名称 即可获取结果集, 并可以将其当作表来使用.
1. 创建视图
--格式: CREATE VIEW 视图名称 AS SQL语句 CREATE VIEW temp1 as SELECT * FROM score WHERE course_id in (1,2)
注意: 视图是动态生成的, 原数据变动它也变动. 视图中不允许操作(增删改), 只能查
2. 删除视图
-- 格式: DROP VIEW 视图名称 DROP VIEW temp1;
3. 修改视图
-- 格式: ALTER VIEW 视图名称 AS SQL语句 ALTER VIEW temp1 as SELECT student.sid, score.course_id,student.sname FROM score LEFT JOIN student on score.student_id=student.sid LEFT JOIN student on score.student_id=student.sid WHERE course_id in (1,2)
4. 使用视图
SELECT * FROM temp1;
存储过程
存储过程是一个SQL语句集合(可写复杂逻辑), 当主动去调用存储过程时, 其中内部的SQL语句会按照逻辑执行.
1. 创建存储过程
-- 创建存储过程 delimiter // -- 将终结符由;改成// CREATE PROCEDURE p1() BEGIN select * from student; END// -- 遇到终结符//表示结束 delimiter ; -- 将终结符改回; -- 执行存储过程 call p1();
对于存储过程, 可以接收参数, 其参数有三类:
- in 仅用于传入参数用
- out 仅用于返回值用
- inout 既可以传入又可以当作返回值
delimiter \\ create procedure p2( in i1 int, in i2 int, inout i3 int, out r1 int ) BEGIN DECLARE temp1 int; DECLARE temp2 int default 0; set temp1 = 1; set r1 = i1 + i2 + temp1 + temp2; set i3 = i3 + 100; SELECT * FROM class; END\\ delimiter ; -- 执行存储过程 set @t1=0; set @t2=3; call p2(1,2,@t1,@t2)
注: 存储过程可以获得两类数据: 普通值, 结果集
delimiter \\ create PROCEDURE p( OUT p_return_code tinyint ) BEGIN DECLARE exit handler for sqlexception BEGIN -- ERROR set p_return_code = 1; rollback; END; DECLARE exit handler for sqlwarning BEGIN -- WARNING set p_return_code = 2; rollback; END; START TRANSACTION; -- 开始事务 DELETE from tb1; insert into tb2(name)values('seven'); COMMIT; -- SUCCESS set p_return_code = 0; END\\ delimiter ; -- 执行 set @i =0; call p1(@i); select @i;
事务:用于将某些操作的多个SQL作为原子性操作, 一旦有某一个出现错误, 即可回滚到原来的状态, 从而保证数据库数据完整性.
innodb引擎有这个机制. 例如转钱: 一个减钱一个加钱(原子性操作), 若有一方转失败, 双方金额回到操作前的数(回滚rollback), 这个过程叫事务. 在这里类似python中try...except...异常处理操作.
delimiter // CREATE PROCEDURE p3 ( ) BEGIN DECLARE ssid INT;-- 自定义变量1 DECLARE ssname VARCHAR ( 50 );-- 自定义变量2 DECLARE done INT DEFAULT FALSE; DECLARE my_cursor CURSOR FOR SELECT sid, sname FROM student; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; OPEN my_cursor; xxoo : LOOP FETCH my_cursor INTO ssid, ssname; IF done THEN LEAVE xxoo; END IF; INSERT INTO teacher(tname) VALUES (ssname); END LOOP xxoo; CLOSE my_cursor; END // delimter;
delimiter \\ CREATE PROCEDURE p3() BEGIN declare p1 int; set @p1 = 11; -- 变量名必须为@xx的形式 PREPARE prod FROM 'select * from tb2 where nid > ?'; EXECUTE prod USING @p1; -- @p1的数值会放到?中 DEALLOCATE prepare prod; END\\ delimiter ;
2. 删除存储过程
DROP PROCEDURE p1;
3. pymysql执行存储过程
import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='gkl273318', db='exercise', charset='utf8') cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) # 执行存储过程, 获取存储过程的结果集, 将返回值设置给 @_存储过程名_序号 = .. r1 = cursor.callproc('p2', args=(1, 22, 3, 4)) # 相当于: # set @_p2_0 = 1 # set @_p2_1 = 22 # set @_p2_2 = 3 # set @_p2_3 = 4 # call p11(1,22,3,4) print(r1) # (1, 22, 3, 4) r2 = cursor.fetchall() print(r2) # 获取执行完存储的参数 cursor.execute("select @_p2_0,@_p2_1,@_p2_2,@_p2_3") result = cursor.fetchall() conn.commit() cursor.close() conn.close() print(result) #[{'@_p2_0': 1, '@_p2_1': 22, '@_p2_2': 103, '@_p2_3': 24}]
触发器
对某个表进行增/删/改操作的前后如果希望触发某个特定的行为时, 可以使用触发器, 即用于定制用户对表的行进行增/删/改前后的行为.
1. 创建基本语法
# 插入前 CREATE TRIGGER tri_before_insert_tb1 BEFORE INSERT ON tb1 FOR EACH ROW BEGIN ... END # 插入后 CREATE TRIGGER tri_after_insert_tb1 AFTER INSERT ON tb1 FOR EACH ROW BEGIN ... END # 删除前 CREATE TRIGGER tri_before_delete_tb1 BEFORE DELETE ON tb1 FOR EACH ROW BEGIN ... END # 删除后 CREATE TRIGGER tri_after_delete_tb1 AFTER DELETE ON tb1 FOR EACH ROW BEGIN ... END # 更新前 CREATE TRIGGER tri_before_update_tb1 BEFORE UPDATE ON tb1 FOR EACH ROW BEGIN ... END # 更新后 CREATE TRIGGER tri_after_update_tb1 AFTER UPDATE ON tb1 FOR EACH ROW BEGIN ... END
例:
delimiter // CREATE TRIGGER tri_before_insert_tb1 BEFORE INSERT ON tb1 FOR EACH ROW BEGIN IF NEW. NAME == 'alan' THEN INSERT INTO tb2 (NAME) VALUES ('aa') END END// delimiter ;
delimiter // CREATE TRIGGER tri_after_insert_tb1 AFTER INSERT ON tb1 FOR EACH ROW BEGIN IF NEW. num = 666 THEN INSERT INTO tb2 (NAME) VALUES ('666'), ('666') ; ELSEIF NEW. num = 555 THEN INSERT INTO tb2 (NAME) VALUES ('555'), ('555') ; END IF; END// delimiter ;
注意: NEW表示即将插入的数据行, OLD表示即将删除的数据行.
注意: 使用删除前触发器, 将删除的值OLD添加到另外一张表. 若是多行数据, 其内部有类似for循环的机制.
2. 删除触发器
DROP TRIGGER tri_after_insert_tb1;
3. 使用触发器
触发器无法由用户直接调用, 而只由于对表的增/删/改操作被动引发的.
-- CREATE TRIGGER tri_before_insert_tb1 BEFORE INSERT ON student FOR EACH ROW -- BEGIN -- INSERT INTO class(caption) VALUES ('测试班'); -- END INSERT INTO student(gender,class_id,sname) VALUES ('男', 1, '阿土');
函数
MySQL中提供了许多内置函数:
CHAR_LENGTH(str) 返回值为字符串str 的长度,长度的单位为字符。一个多字节字符算作一个单字符。 对于一个包含五个二字节字符集, LENGTH()返回值为 10, 而CHAR_LENGTH()的返回值为5。 CONCAT(str1,str2,...) 字符串拼接 如有任何一个参数为NULL ,则返回值为 NULL。 CONCAT_WS(separator,str1,str2,...) 字符串拼接(自定义连接符) CONCAT_WS()不会忽略任何空字符串。 (然而会忽略所有的 NULL)。 CONV(N,from_base,to_base) 进制转换 例如: SELECT CONV('a',16,2); 表示将 a 由16进制转换为2进制字符串表示 FORMAT(X,D) 将数字X 的格式写为'#,###,###.##',以四舍五入的方式保留小数点后 D 位, 并将结果以字符串的形式返回。若 D 为 0, 则返回结果不带有小数点,或不含小数部分。 例如: SELECT FORMAT(12332.1,4); 结果为: '12,332.1000' INSERT(str,pos,len,newstr) 在str的指定位置插入字符串 pos:要替换位置其实位置 len:替换的长度 newstr:新字符串 特别的: 如果pos超过原字符串长度,则返回原字符串 如果len超过原字符串长度,则由新字符串完全替换 INSTR(str,substr) 返回字符串 str 中子字符串的第一个出现位置。 LEFT(str,len) 返回字符串str 从开始的len位置的子序列字符。 LOWER(str) 变小写 UPPER(str) 变大写 LTRIM(str) 返回字符串 str ,其引导空格字符被删除。 RTRIM(str) 返回字符串 str ,结尾空格字符被删去。 SUBSTRING(str,pos,len) 获取字符串子序列 LOCATE(substr,str,pos) 获取子序列索引位置 REPEAT(str,count) 返回一个由重复的字符串str 组成的字符串,字符串str的数目等于count 。 若 count <= 0,则返回一个空字符串。 若str 或 count 为 NULL,则返回 NULL 。 REPLACE(str,from_str,to_str) 返回字符串str 以及所有被字符串to_str替代的字符串from_str 。 REVERSE(str) 返回字符串 str ,顺序和字符顺序相反。 RIGHT(str,len) 从字符串str 开始,返回从后边开始len个字符组成的子序列 SPACE(N) 返回一个由N空格组成的字符串。 SUBSTRING(str,pos) , SUBSTRING(str FROM pos) SUBSTRING(str,pos,len) , SUBSTRING(str FROM pos FOR len) 不带有len 参数的格式从字符串str返回一个子字符串,起始于位置 pos。带有len参数的格式从字符串str返回一个长度同len字符相同的子字符串,起始于位置 pos。 使用 FROM的格式为标准 SQL 语法。也可能对pos使用一个负值。假若这样,则子字符串的位置起始于字符串结尾的pos 字符,而不是字符串的开头位置。在以下格式的函数中可以对pos 使用一个负值。 mysql> SELECT SUBSTRING('Quadratically',5); -> 'ratically' mysql> SELECT SUBSTRING('foobarbar' FROM 4); -> 'barbar' mysql> SELECT SUBSTRING('Quadratically',5,6); -> 'ratica' mysql> SELECT SUBSTRING('Sakila', -3); -> 'ila' mysql> SELECT SUBSTRING('Sakila', -5, 3); -> 'aki' mysql> SELECT SUBSTRING('Sakila' FROM -4 FOR 2); -> 'ki' TRIM([{BOTH | LEADING | TRAILING} [remstr] FROM] str) TRIM(remstr FROM] str) 返回字符串 str , 其中所有remstr 前缀和/或后缀都已被删除。若分类符BOTH、LEADIN或TRAILING中没有一个是给定的,则假设为BOTH 。 remstr 为可选项,在未指定情况下,可删除空格。 mysql> SELECT TRIM(' bar '); -> 'bar' mysql> SELECT TRIM(LEADING 'x' FROM 'xxxbarxxx'); -> 'barxxx' mysql> SELECT TRIM(BOTH 'x' FROM 'xxxbarxxx'); -> 'bar' mysql> SELECT TRIM(TRAILING 'xyz' FROM 'barxxyz'); -> 'barx'
官方文档
1. 自定义函数:
delimiter \\ CREATE FUNCTION f1( i1 int, i2 int) returns int BEGIN -- 不能获取结果集(不能使用SQL语句) DECLARE num int; SET num = i1 + i2; return(num); END \\ delimiter ;
2. 删除自定义函数:
DROP FUNCTION f1;
3. 执行自定义函数:
# 获取返回值 DECLARE @i VARCHAR(32); SELECT UPPER('alex') into @i; SELECT @i; # 在查询中使用 SELECT f1(11,nid) ,name FROM tb2;
其他
1. 条件语句
delimiter \\ CREATE PROCEDURE proc_if () BEGIN declare i int default 0; if i = 1 THEN SELECT 1; ELSEIF i = 2 THEN SELECT 2; ELSE SELECT 7; END IF; END\\ delimiter ;
2. 循环语句
delimiter \\ CREATE PROCEDURE proc_while () BEGIN DECLARE num INT ; SET num = 0 ; WHILE num < 10 DO SELECT num ; SET num = num + 1 ; END WHILE ; END\\ delimiter ;
delimiter \\ CREATE PROCEDURE proc_repeat () BEGIN DECLARE i INT ; SET i = 0 ; repeat select i; set i = i + 1; until i >= 5 end repeat; END\\ delimiter ;
BEGIN declare i int default 0; loop_label: loop --loop_label为名字 set i=i+1; if i<8 then iterate loop_label; end if; if i>=10 then leave loop_label; end if; select i; end loop loop_label; END
3. 动态执行SQL语句**
将sql语句作为字符串参数传入
delimiter \\ DROP PROCEDURE IF EXISTS proc_sql \\ CREATE PROCEDURE proc_sql () BEGIN declare p1 int; set @p1 = 11; -- 变量名必须为@xx的形式 PREPARE prod FROM 'select * from tb2 where nid > ?'; EXECUTE prod USING @p1; -- @p1的数值会放到?中 DEALLOCATE prepare prod; END\\ delimiter ;
索引****
索引是数据库中专门用于帮助用户快速查询数据的一种数据结构. 类似于字典中的目录, 查找字典内容时可以根据目录查找到数据的存放位置, 然后直接获取即可.
索引是表的目录, 在查找内容之前可以先在目录中查找索引位置, 以此快速定位查询数据. 对于索引, 会保存在额外的文件中.
功能: 1. 约束 2. 加速查找
1 30 2 3 10 40 4 5 5 15 35 66 6 7 1 6 11 19 21 39 55 100
索引将数据列中的数据通过算法转化成数字存入索引文件, 该数字表示数据列中的数据在硬盘上的位置. 索引文件以B-tree(一种多路搜索树, 并不是二叉树. 还有一种B+tree, B-tree的改进)的方式存放数据. 假设以上为一个索引文件, 一共四行, 所以可以查2**4-1=15个数据, 30左边为小于它的数, 右边为大于它的数, 以此类推. 所以只要最多4次就可以查到需要的索引, 再通过索引去数据表中取得数据. 而没有索引的话则需要从上到下一个个搜寻, 十分之慢.
创建索引的代价: 使得增/删/改操作会变慢, 且因为多生成索引文件, 所以多占用点硬盘资源.
索引种类
MySQL中常见索引有:
- 普通索引
- 唯一索引
- 主键索引
- 组合索引
1. 普通索引:仅加速查询
create table in1( nid int not null auto_increment primary key, name varchar(32) not null, email varchar(64) not null, extra text, index ix_name (name) ) 或者创完表之后再加索引 create index 索引名 on 表名(列名) -- 注意: 对于创建索引时如果是BLOB 和 TEXT 类型, 必须指定length. create index ix_extra on in1(extra(32));
DROP 索引名 on 表名;
2. 唯一索引:加速查询 + 列值唯一的约束(可以有null)
create table in1( nid int not null auto_increment primary key, name varchar(32) not null, email varchar(64) not null, extra text, unique ix_name (name) ) 或者创建完表之后再添加索引 create unique index 索引名 on 表名(列名)
DROP unique index 索引名 on 表名
3. 主键索引:加速查询 + 列值唯一的约束 + 表中只有一个(不可以有null)
create table in1( nid int not null auto_increment primary key, name varchar(32) not null, email varchar(64) not null, extra text, index ix_name (name) ) OR create table in1( nid int not null auto_increment, name varchar(32) not null, email varchar(64) not null, extra text, primary key(ni1), index ix_name (name) ) 或者创建完表之后再添加索引 alter table 表名 add primary key(列名);
alter table 表名 drop primary key; alter table 表名 modify 列名 int, drop primary key;
4. 组合索引:多列值组成一个索引, 专门用于组合搜索,其效率大于索引合并
create table in3( nid int not null auto_increment primary key, name varchar(32) not null, email varchar(64) not null, extra text ) -- create 索引名 on 表名(列名,列名,...) create index ix_name_email on in3(name,email);
注意:对于同时搜索n个条件时,组合索引的性能好于多个单一索引合并
5. 全文索引:对文本的内容进行分词, 进行搜索
索引合并, 使用多个单列索引(单独索引)组合搜索, 跟组合索引不同, 因为组合索引有最左前缀的限制, 但是索引合并没有. 但是效率没有组合索引快.
覆盖索引, select的数据列只用从索引中就能够取得, 不必读取数据行, 即查询列要被所建的索引覆盖.
例:
select * from tb where nid=1 -- 先去索引文件中找, 再去数据表找. select nid from tb where nid < 10 -- 直接去索引文件中找 只需要在索引文件中就能获取到数据时, 不用去数据表中操作, 就为覆盖索引.
相关命令
-- 查看表结构 desc 表名 -- 查看生成表的SQL show create table 表名 -- 查看索引 show index from 表名 -- 查看执行时间 set profiling = 1; SQL... show profiles;
正确使用索引
数据库表中添加索引后确实会加快查询速度, 但前提必须是正确的使用索引来查询, 如果以错误的方式使用, 则即使建立索引也不会取得加速效果.
以下语句会使索引不会生效:
-- like '%xx' select * from tb1 where name like '%cn'; 而 select * from tb1 where name like 'cn%'; 才会使索引生效 -- 使用函数 select * from tb1 where reverse(name) = 'charon'; -- or select * from tb1 where nid = 1 or email = 'charon@live.com'; 特别的: 当or条件中有未建立索引的列才失效, 以下会走索引 select * from tb1 where nid = 1 or name = 'alan'; -- nid和name都是索引 select * from tb1 where nid = 1 or email = 'charon@live.com' and name = 'charon' -- nid和name都是索引 -- 类型不一致 如果列是字符串类型, 传入条件是必须用引号引起来, 不然索引不会生效 select * from tb1 where name = 999; -- != select * from tb1 where name != 'alan' 特别的: 如果是主键, 则还是会走索引 select * from tb1 where nid != 123 -- > select * from tb1 where name > 'alan' 特别的: 如果是主键或索引是整数类型, 则还是会走索引 select * from tb1 where nid > 123 select * from tb1 where num > 123 -- order by select email from tb1 order by name desc; 当根据索引排序时候, 选择的映射如果不是索引, 则不走索引 特别的: 如果对主键排序,则还是走索引: select * from tb1 order by nid desc; -- 组合索引最左前缀(最左匹配) 如果组合索引为: (name,email) name and email -- 使用索引, 因为两者为组合索引 name -- 使用索引, 因为最左前缀, name在左边 email -- 不使用索引, 因为email在右边, 不符合最左前缀
注意事项
- 避免使用select * - count(1)或count(列) 代替 count(*) - 创建表时尽量时 char 代替 varchar - 表的字段顺序固定长度(定长)的字段优先 - 组合索引代替多个单列索引(经常使用多个条件查询时) - 尽量使用短索引 - 使用连接(JOIN)来代替子查询(Sub-Queries) - 连表时注意条件类型需一致 - 索引散列值(重复少)不适合建索引. 例: 性别非男即女, 不适合做索引
执行计划(Execution Plan)
-- explain SQL语句 explain select * from tb1;
用于显示SQL执行信息参数(可以相对比较准确表达出当前SQL运行状况), 根据参考信息可以进行SQL优化
![]()
![]()
重点看 type 和 rows.
-- id 查询顺序标识. id列数字越大越先执行, 如果数字一样大, 那么就从上往下依次执行. id列为null的就表是这是一个结果集, 不需要使用它来进行查询. 注: 如果使用union连接, 其值可能为null -- select_type 查询类型 SIMPLE 简单查询 PRIMARY 最外层查询 SUBQUERY 映射为子查询 DERIVED 子查询 UNION 联合 UNION RESULT 使用联合的结果 ... -- table 正在访问的表名 -- type ***** 查询时的访问方式, 性能: all < index < range < index_merge < ref_or_null < ref < eq_ref < system/const 1. ALL - 全表扫描, 对于数据表从头到尾找一遍 select * from tb1; 特别的: 如果有limit限制, 则找到之后就不在继续向下扫描 select * from tb1 where email = 'alan@live.com' select * from tb1 where email = 'alan@live.com' limit 1; 虽然上述两个语句都会进行全表扫描,第二句使用了limit,则找到一个后就不再继续扫描 2. INDEX - 全索引扫描,对索引从头到尾找一遍 select nid from tb1; 3. RANGE - 对索引列进行范围查找 select * from tb1 where name < 'alan'; 注: between and in > >= < <= 操作 注意:!= 和 > 符号会使索引无法生效 4. INDEX_MERGE - 合并索引,使用多个单列索引搜索 select * from tb1 where name = 'alan' or nid in (11,22,33); 5. REF - 根据索引查找一个或多个值 select * from tb1 where name = 'charon'; 6. EQ_REF - 连接时使用primary key 或 unique类型 select tb2.nid,tb1.name from tb2 left join tb1 on tb2.nid = tb1.nid; 7. CONST - 常量 表最多有一个匹配行,因为仅有一行,在这行的列值可被优化器剩余部分认为是常数,const表很快,因为它们只读取一次. select nid from tb1 where nid = 2 ; 8. SYSTEM - 系统 表仅有一行(=系统表). 这是const联接类型的一个特例. select * from (select nid from tb1 where nid = 1) as A; -- possible_keys 可能使用的索引 -- key 真实使用的索引 -- key_len MySQL中使用索引字节长度 -- rows mysql估计为了找到所需的行而要读取的行数 ------ 只是预估值 -- extra 该列包含MySQL解决查询的详细信息 “Using index” 此值表示mysql将使用覆盖索引,以避免访问表。不要把覆盖索引和index访问类型弄混了。 “Using where” 这意味着mysql服务器将在存储引擎检索行后再进行过滤,许多where条件里涉及索引中的列,当(并且如果)它读取索引时,就能被存储引擎检验,因此不是所有带where子句的查询都会显示“Using where”。有时“Using where”的出现就是一个暗示:查询可受益于不同的索引。 “Using temporary” 这意味着mysql在对查询结果排序时会使用一个临时表。 “Using filesort” 这意味着mysql会对结果使用一个外部索引排序,而不是按索引次序从表里读取行。mysql有两种文件排序算法,这两种排序方式都可以在内存或者磁盘上完成,explain不会告诉你mysql将使用哪一种文件排序,也不会告诉你排序会在内存里还是磁盘上完成。 “Range checked for each record(index map: N)” 这个意味着没有好用的索引,新的索引将在联接的每一行上重新估算,N是显示在possible_keys列中索引的位图,并且是冗余的。
慢日志查询
慢查询日志是MySQL提供的一种日志记录, 用来记录在MySQL中响应时间超过阈值的语句, 具体指运行时间超过long_query_time值的SQL, 则会被记录到慢查询日志中.
两种方式可以开启慢日志:
1. 写一个配置文件(推荐)
........(不会写)......写配置文件操作, 然后以下参数写入即可.
slow_query_log = ON 是否开启慢日志记录, 默认为OFF
long_query_time = 2 时间限制, 超过此时间则记录, 默认值为10
slow_query_log_file = /usr/slow.log path 日志文件
log_queries_not_using_indexes = ON 为使用索引的搜索是否记录
2. 直接在内存中修改(不推荐, 因为重启失效)
在terminal输入:
查看当前配置信息:
show variables like '%query%'
修改当前配置:
set global 变量名 = 值

set global slow_query_log = ON;
...

浙公网安备 33010602011771号