码迷,mamicode.com
首页 > 数据库 > 详细

MySQL(2)

时间:2018-03-05 12:02:55      阅读:204      评论:0      收藏:0      [点我收藏+]

标签:状态   cti   原则   动态   第一个   锁定   优化   字典   映射   

视图

视图是一个虚拟表(非真实存在),其本质是【根据SQL语句获取动态的数据集,并为其命名】,用户使用时只需使用【名称】即可获取结果集,并可以将其当作表来使用。

技术分享图片
SELECT
    *
FROM
    (
        SELECT
            nid,
            NAME
        FROM
            tb1
        WHERE
            nid > 2
    ) AS A
WHERE
    A. NAME > alex;
临时表搜索

1.创建视图

技术分享图片
--格式:CREATE VIEW 视图名称 AS  SQL语句
CREATE VIEW v1 AS 
SELET nid, 
    name
FROM
    A
WHERE
    nid > 4
View Code

2.删除视图

技术分享图片
--格式:DROP VIEW 视图名称

DROP VIEW v1
View Code

3.修改视图

技术分享图片
-- 格式:ALTER VIEW 视图名称 AS SQL语句

ALTER VIEW v1 AS
SELET A.nid,
    B. NAME
FROM
    A
LEFT JOIN B ON A.id = B.nid
LEFT JOIN C ON A.id = C.nid
WHERE
    A.id > 2
AND C.nid < 5
View Code

4.使用视图

使用视图时,将其当作表进行操作即可,由于视图是虚拟表,所以无法使用其对真实表进行创建、更新和删除操作,仅能做查询用。

技术分享图片
select * from v1
View Code

 

存储过程

 存储过程是一个SQL语句集合,当主动去调用存储过程时,其中内部的SQL语句会按照逻辑执行。

1.创建存储过程

技术分享图片
-- 创建存储过程

delimiter //     # ‘;’表示sql语句的终止符,这里的delimiter表示将终止符更改为‘//’
create procedure p1()
BEGIN
    select * from t1;
END//
delimiter ;



-- 执行存储过程

call p1()
无参数的存储过程

对于存储过程,可以接收参数,其参数有三类:

    • in          仅用于传入参数用(让存储过程内部使用)
    • out        仅用于返回值用(创建一个变量,这个变量的值在存储过程中进行赋值后返回)
    • inout     既可以传入又可以当作返回值
技术分享图片
 1 -- 创建存储过程
 2 delimiter \ 3 create procedure p1(
 4     in i1 int,         #i1 =1
 5     in i2 int,         #i2 =2
 6     inout i3 int,    #即i3 = 123
 7     out r1 int       #即r1 = null
 8 )
 9 BEGIN
10     DECLARE temp1 int;  #DECLARE在存储过程内部声明变量时,必须使用
11     DECLARE temp2 int default 0;
12     
13     set temp1 = 1; #set对变量进行赋值
14 
15     set r1 = 10;  #这时会将在存储过程中设置的值返回给变量t1
16     
17     set i3 = 100;             #这时会将在存储过程中设置的值返回给变量i3
18 
19     select * from v1;    #执行存储过程时还可以返回结构集
20 
21 
22 end\23 delimiter ;
24 
25 -- 执行存储过程
26 set @t1 =123;    #创建一个变量t1,这个变量的值在存储过程中进行赋值后返回(默认不设置值则为null)
27 set @t2 =0;
28 SELECT @t1,@t2   # 123 null
29 CALL p1 (1, 2 ,@t1, @t2);     #@t1, @t2 将引用传递给存储过程,值不会传入。
30 SELECT @t1,@t2;      #输出存储过程返回的值  10 100
有参数的存储过程

 

技术分享图片
1 delimiter //
2 create procedure p1()
3 begin
4      select * from v1;
5 end //
6 delimiter ;
1.结果集

 

技术分享图片
                    delimiter //
                    create procedure p2(
                        in n1 int,
                        inout n3 int,
                        out n2 int,
                    )
                    begin
                        declare temp1 int ;
                        declare temp2 int default 0;

                        select * from v1;
                        set n2 = n1 + 100;
                        set n3 = n3 + n1 + 100;
                    end //
                    delimiter ;
2.结果集+out值

 2.删除存储过程

技术分享图片
drop procedure proc_name;
View Code

3.执行存储过程

技术分享图片
-- 无参数
call proc_name()

-- 有参数,全in
call proc_name(1,2)

-- 有参数,有in,out,inout
set @t1=0;
set @t2=3;
call proc_name(1,2,@t1,@t2)
执行存储过程

 

技术分享图片
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import pymysql

conn = pymysql.connect(host=127.0.0.1, port=3306, user=root, passwd=123, db=t1)
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
# 执行存储过程,获取存储过程的结果集,将返回值设置给了 @_存储过程名_序号 =返回结果1 ...
cursor.callproc(p1, args=(1, 22, 3, 4))
# 获取执行完存储的参数
cursor.execute("select @_p1_0,@_p1_1,@_p1_2,@_p1_3")
result = cursor.fetchall()

conn.commit()
cursor.close()
conn.close()


print(result)
pymysql执行存储过程

 

 触发器

 对某个表进行【增/删/改】操作的前后如果希望触发某个特定的行为时,可以使用触发器,触发器用于定制用户对表的行进行【增/删/改】前后的行为。(触发器器中无查询)

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
View Code
技术分享图片
delimiter //
CREATE TRIGGER tri_before_insert_tb1 BEFORE INSERT ON tb1 FOR EACH ROW
BEGIN

IF NEW. NAME == alex THEN
    INSERT INTO tb2 (NAME)
VALUES
    (aa)
END
END//
delimiter ;

#使用触发器
insert into tb1(name,age,gender) values(alex,18,)
#NEW.name=‘alex‘
#NEW.age=18
#NEW.gender=‘男‘

###############################################
#向student表插入数据前先对class表进行操作
delimiter //
CREATE TRIGGER tri_before_insert_tb1 BEFORE INSERT ON student FOR EACH ROW
BEGIN
      insert  into class(caption) values(99999);
END//
delimiter ;
插入前触发器

 

特别的:NEW表示即将插入的数据行(即new就封装了用户新提交的数据);OLD表示即将删除的数据行(即old就封装了用户即将删除的数据)。

update tb1 set name=‘lriwu‘ where nid=1  #OLD.name=‘alex‘  NEW.name=‘lriwu‘

2.删除触发器

技术分享图片
DROP TRIGGER tri_after_insert_tb1;
View Code

3.使用触发器

触发器无法由用户直接调用,而是对表的【增/删/改】操作被动引发的。

技术分享图片
insert into tb1(num) values(666)
View Code

 

事物

事务用于将某些操作的多个SQL作为原子性操作,一旦有某一个出现错误,即可回滚到原来的状态,从而保证数据库数据完整性。innodb引擎支持事物。

技术分享图片
 1 delimiter \ 2 create PROCEDURE p1(
 3     OUT p_return_code tinyint
 4 )
 5 BEGIN 
 6   DECLARE exit handler for sqlexception 
 7   BEGIN 
 8     -- ERROR 
 9     set p_return_code = 1; 
10     rollback; 
11   END; 
12  
13   DECLARE exit handler for sqlwarning    #创建一个sql的异常处理
14   BEGIN 
15     -- WARNING 
16     set p_return_code = 2; 
17     rollback; 
18   END; 
19  
20   START TRANSACTION;      #表示开始一个事物
21     DELETE from tb1;
22     insert into tb2(name)values(seven);
23   COMMIT;     #中间的代码就表示要执行的原子性操作
24  
25   -- SUCCESS 
26   set p_return_code = 0; 
27  
28   END\29 delimiter ;
View Code

 

1 set @i =0;
2 call p1(@i);
3 select @i;

 

函数

函数中不能返回结果集,也不能执行sql语句。

1.mysql内置函数:

MySQL中提供了许多内置函数,例如:

技术分享图片
  1     CHAR_LENGTH(str)   
  2         返回值为字符串str 的长度,长度的单位为字符。一个多字节字符算作一个单字符。
  3         对于一个包含五个二字节字符集, LENGTH()返回值为 10, 而CHAR_LENGTH()的返回值为5。
  4         #select CHAR_LENGTH(‘lriwu‘)    5
  5 
  6     CONCAT(str1,str2,...)
  7         字符串拼接
  8         如有任何一个参数为NULL ,则返回值为 NULL。
  9         #select concat(‘lr‘,‘iw‘,‘uu‘)    lriwuu
 10   
 11     CONCAT_WS(separator,str1,str2,...)
 12         字符串拼接(自定义连接符)
 13         CONCAT_WS()不会忽略任何空字符串。 (然而会忽略所有的 NULL)。
 14         #select concat_ws(‘_‘,‘xx‘,‘oo‘)    xx_oo
 15 
 16     CONV(N,from_base,to_base)
 17         进制转换
 18         例如:
 19             SELECT CONV(a,16,2); 表示将 a 由16进制转换为2进制字符串表示  1010
 20 
 21     FORMAT(X,D)
 22         将数字X 的格式写为#,###,###.##,以四舍五入的方式保留小数点后 D 位, 并将结果以字符串的形式返回。若  D 为 0, 则返回结果不带有小数点,或不含小数部分。
 23         例如:
 24             SELECT FORMAT(12332.1,4); 结果为: 12,332.1000
 25     INSERT(str,pos,len,newstr)
 26         在str的指定位置插入字符串
 27             pos:要替换位置起始位置
 28             len:替换的长度
 29             newstr:新字符串
 30         特别的:
 31             如果pos超过原字符串长度,则返回原字符串
 32             如果len超过原字符串长度,则由新字符串完全替换
 33           select insert (alex,1,1,G)    Glex
 34           select insert (alex,1,2,GD)    GDex
 35           select insert (lriwu,2,2,GD)    aGDx
 36           select insert (lriwu,2,2,GDBX)    aGDBXx
 37           select insert (lriwu,2,2,G)    aGx
 38 
 39 
 40     INSTR(str,substr)
 41         返回字符串 str 中子字符串的第一个出现位置。 
 42 
 43     LEFT(str,len)
 44         返回字符串str 从开始的len位置的子序列字符。
 45         select left(alex,3)   ale
 46         select right(alex,2)   ex
 47 
 48 
 49     LOWER(str)
 50         变小写
 51 
 52     UPPER(str)
 53         变大写
 54 
 55     LTRIM(str)
 56         返回字符串 str ,其引导空格字符被删除。
 57     RTRIM(str)
 58         返回字符串 str ,结尾空格字符被删去。
 59     TRIM(str)
 60         将两边的空白删除。
 61 
 62     SUBSTRING(str,pos,len)
 63         获取字符串子序列
 64         select substring(alex,2,1)   l
 65 
 66     LOCATE(substr,str,pos)
 67         获取子序列索引位置,从pos位置开始往后找
 68        select locate(ex,alexalex,1)    3
 69        select locate(ex,alexalex,4)    7
 70 
 71     REPEAT(str,count)
 72         返回一个由重复的字符串str 组成的字符串,字符串str的数目等于count 。
 73         若 count <= 0,则返回一个空字符串。
 74         若str 或 count 为 NULL,则返回 NULL 。
 75         select repeat(alex,1)  alex
 76         select repeat(alex,2)  alexalex
 77 
 78     REPLACE(str,from_str,to_str)
 79         返回字符串str 以及所有被字符串to_str替代的字符串from_str 。
 80         select replace(alex,le,GD)   aGDx
 81         select replace(alex,le,GDBX)   aGDBXx
 82 
 83     REVERSE(str)
 84         返回字符串 str ,顺序和字符顺序相反。
 85     RIGHT(str,len)
 86         从字符串str 开始,返回从后边开始len个字符组成的子序列
 87 
 88     SPACE(N)
 89         返回一个由N空格组成的字符串。
 90 
 91     SUBSTRING(str,pos) , SUBSTRING(str FROM pos) SUBSTRING(str,pos,len) , SUBSTRING(str FROM pos FOR len)
 92         不带有len 参数的格式从字符串str返回一个子字符串,起始于位置 pos。带有len参数的格式从字符串str返回一个长度同len字符相同的子字符串,起始于位置 pos。 使用 FROM的格式为标准 SQL 语法。也可能对pos使用一个负值。假若这样,则子字符串的位置起始于字符串结尾的pos 字符,而不是字符串的开头位置。在以下格式的函数中可以对pos 使用一个负值。
 93 
 94         mysql> SELECT SUBSTRING(Quadratically,5);
 95             -> ratically
 96 
 97         mysql> SELECT SUBSTRING(foobarbar FROM 4);
 98             -> barbar
 99 
100         mysql> SELECT SUBSTRING(Quadratically,5,6);
101             -> ratica
102 
103         mysql> SELECT SUBSTRING(Sakila, -3);
104             -> ila
105 
106         mysql> SELECT SUBSTRING(Sakila, -5, 3);
107             -> aki
108 
109         mysql> SELECT SUBSTRING(Sakila FROM -4 FOR 2);
110             -> ki
111 
112     TRIM([{BOTH | LEADING | TRAILING} [remstr] FROM] str) TRIM(remstr FROM] str)
113         返回字符串 str , 其中所有remstr 前缀和/或后缀都已被删除。若分类符BOTH、LEADIN或TRAILING中没有一个是给定的,则假设为BOTH 。 remstr 为可选项,在未指定情况下,可删除空格。
114 
115         mysql> SELECT TRIM(  bar   );
116                 -> bar
117 
118         mysql> SELECT TRIM(LEADING x FROM xxxbarxxx);
119                 -> barxxx
120 
121         mysql> SELECT TRIM(BOTH x FROM xxxbarxxx);
122                 -> bar
123 
124         mysql> SELECT TRIM(TRAILING xyz FROM barxxyz);
125                 -> barx
部分内置函数

2.mysql自定义函数:

技术分享图片
 1 delimiter \ 2 create function f1(
 3     i1 int,
 4     i2 int)
 5 returns int           #返回的是int类型
 6 BEGIN
 7     declare num int;
 8     set num = i1 + i2;
 9     return(num);
10 END \11 delimiter ;
12 
13 select f1(1,2)   #返回3
View Code

 

 3.删除函数

技术分享图片
drop function func_name;
View Code

4.执行函数

技术分享图片
 1 # 获取返回值
 2 declare @i VARCHAR(32);      #声明变量i
 3 select UPPER(alex) into @i;   #将‘ALEX‘赋值给i
 4 SELECT @i;
 5 #函数不支持sql语句,但是支持以上的方式对变量进行赋值
 6 declare a int;
 7 set a = 123;
 8 select nid into a from student where name = lriwu   #将查询到的nid赋值给a
 9 
10 
11 # 在查询中使用
12 select f1(11,nid) ,name from tb2;
View Code

 

 

索引

 索引,是数据库中专门用于帮助用户快速查询数据的一种数据结构。类似于字典中的目录,查找字典内容时可以根据目录查找到数据的存放位置,然后直接获取即可。

索引功能:

约束:主键索引,外键索引,唯一索引,普通索引,组合索引

加速查找

创建索引内部过程:

创建表:

生成数据文件并保存在硬盘上。

创建索引:

如:name列创建索引

-name列数据全部拿到;

-将name列每一个数据转化成一个数字。

-将这些数字以一定的规则进行存放,如B-tree

1                     30
2  
3         10                        40
4  
5    5         15            35             66
6  
7 1   6     11    19      21      39     55     100

-将这些数字存放至文件即索引文件并保存在硬盘上。

-用户通过name查找时,先键name转化成数字,根据数字在索引文件中查找,找到后直接从数据表找到数据在硬盘中的存放位置。加速查找。

索引的种类

普通索引:

普通索引仅有一个功能:加速查询。

技术分享图片
1 create table in1(
2     nid int not null auto_increment primary key,
3     name varchar(32) not null,
4     email varchar(64) not null,
5     extra text,
6     index ix_name (name)
7 )
创建表+索引

 

技术分享图片
create index index_name on table_name(column_name)
创建索引

 

 

技术分享图片
drop index_name on table_name;
删除索引

 

技术分享图片
show index from table_name;
查看索引

 

 注意:对于创建索引时如果是BLOB 和 TEXT 类型,必须指定length。

技术分享图片
create index ix_extra on in1(extra(32));
View Code

 

唯一索引:

唯一索引有两个功能:加速查询 和 唯一约束(可含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 表名
删除唯一索引

 

主键索引:

主键有两个功能:加速查询 和 唯一约束(不可含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;
删除主键索引

  

组合索引:

组合索引是将n个列组合成一个索引。

其应用场景为:频繁的同时使用n列来进行查询,如:where n1 = ‘alex‘ and n2 = 666。 

技术分享图片
create table in3(
    nid int not null auto_increment primary key,
    name varchar(32) not null,
    email varchar(64) not null,
    extra text
)
创建表

 

普通组合索引:无约束

技术分享图片
create index ix_name_email on in3(name,email);
View Code

联合唯一索引:有约束,两列数据同时不相同,才能插入,不然报错。

如上创建组合索引之后,查询:(最左匹配原则)

      • name and email  -- 使用索引
      • name                 -- 使用索引
      • email                 -- 不使用索引

注意:对于同时搜索n个条件时,组合索引的性能好于多个单一索引合并。

 

覆盖索引:

如:

select * from tb where nid=1;    #nid是主键索引

#先去索引中查找

#再去数据表中查找

select nid from tb where nid<10

#只需要在索引表中查找就能获取到数据,就无需到数据表中查找,这种就称为覆盖索引。

 

合并索引: 

nid name(添加一个单独索引) email(添加一个单独索引) pwd

select * from tb where name=‘lriwu‘         #走name索引

select * from tb where email=‘33@qq.com‘   #走email索引 

select * from tb where name=‘lriwu‘ or email=‘33@qq.com‘   #使用了两个索引合并来搜索,这就称为合并索引

 

nid name email(name和email使用组合索引) pwd

select * from tb where name=‘lriwu‘         #走name索引

select * from tb where email=‘33@qq.com‘   #无法使用索引进行搜索

select * from tb where name=‘lriwu‘ or email=‘33@qq.com‘   #使用组合索引来搜索

 

合并索引和组合索引的区别:

合并索引硬盘上存在两个索引表,组合索引在硬盘上只有一个索引表。性能上组合索引会比合并索引快。

 

案例:

用户表:

nid  username password

1      a               123

2      b               123

这种一般只存在以下两种查询方式:

select * from tb where username=‘xx‘  password=‘xx‘

select * from tb where username=‘xx‘ 

这种情况下,要想使用两种查询都能使用索引来查找,这时就可以采用组合索引(就没必要使用合并索引了)

 

执行计划:相对比较准确的表达出当前SQL语句的运行状况,如查询是否走索引。

explain + 查询SQL - 用于显示SQL执行信息参数,根据参考信息可以进行SQL优化

1 mysql> explain select * from tb2;
2 +----+-------------+-------+------+---------------+------+---------+------+------+-------+
3 | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra |
4 +----+-------------+-------+------+---------------+------+---------+------+------+-------+
5 |  1 | SIMPLE      | tb2   | ALL  | NULL          | NULL | NULL    | NULL |    2 | NULL  |
6 +----+-------------+-------+------+---------------+------+---------+------+------+-------+
7 1 row in set (0.00 sec)
技术分享图片
    id
        查询顺序标识
            如:mysql> explain select * from (select nid,name from tb1 where nid < 10) as B;
            +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
            | id | select_type | table      | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
            +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
            |  1 | PRIMARY     | <derived2> | ALL   | NULL          | NULL    | NULL    | NULL |    9 | NULL        |
            |  2 | DERIVED     | tb1        | range | PRIMARY       | PRIMARY | 8       | NULL |    9 | Using where |
            +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
        特别的:如果使用union连接气值可能为null
(name(普通索引)和nid(主键索引)是索引列)

    select_type
        查询类型
            SIMPLE          简单查询
            PRIMARY         最外层查询
            SUBQUERY        映射为子查询
            DERIVED         子查询
            UNION           联合
            UNION RESULT    使用联合的结果
            ...
    table
        正在访问的表名


    type
        查询时的访问方式,性能:all < index < range < index_merge < ref_or_null < ref < eq_ref < system/const
            ALL             全表扫描,对于数据表从头到尾找一遍
                            select * from tb1;
                            特别的:如果有limit限制,则找到之后就不在继续向下扫描
                                   select * from tb1 where email = seven@live.com
                                   select * from tb1 where email = seven@live.com limit 1;
                                   虽然上述两个语句都会进行全表扫描,第二句使用了limit,则找到一个后就不再继续扫描。

            INDEX           全索引扫描,对索引从头到尾找一遍
                            select nid from tb1;

            RANGE          对索引列进行范围查找
                            select *  from tb1 where name < alex;  #name列时索引列
                            PS:
                                between and
                                in
                                >   >=  <   <=  操作
                                注意:!= 和 > 符号即使是对索引列进行范围查找不走索引


            INDEX_MERGE     合并索引,使用多个单列索引搜索
                            select *  from tb1 where name = alex or nid in (11,22,33);

            REF             根据索引(普通索引)查找一个或多个值
                            select *  from tb1 where name = seven;

            EQ_REF          连接时使用primary key(主键索引) 或 unique(唯一索引)类型进行查询
                            select tb2.nid,tb1.name from tb2 left join tb1 on tb2.nid = tb1.nid;



            CONST           常量
                            表最多有一个匹配行,因为仅有一行,在这行的列值可被优化器剩余部分认为是常数,const表很快,因为它们只读取一次。
                            select nid from tb1 where nid = 2 ;

            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列中索引的位图,并且是冗余的。
View Code

 

 正确使用索引

数据库表中添加索引后确实会让查询速度起飞,但前提必须是正确的使用索引来查询,如果以错误的方式使用,则即使建立索引也会不奏效。
即使建立索引,索引也不会生效:

--tb1中nid主键约束,name/num普通索引
- like %xx
    select * from tb1 where name like %cn;   (不走索引)
    select * from tb1 where name like cn%;   (走索引)
- 使用函数 
    select * from tb1 where reverse(name) = wupeiqi; (不走索引,name是索引,但是经过函数处理后查询就不走索引了)
    select * from tb1 where substring(name,1,3)=lriwu; (不走索引)
-or
    select * from tb1 where nid = 1 or email = seven@live.com;(nid是索引列,email不是索引列,这里不走索引)
    特别的:当or条件中有未建立索引的列才失效,以下会走索引
            select * from tb1 where nid = 1 or name = seven;
            select * from tb1 where nid = 1 or email = seven@live.com and name = alex
- 类型不一致
    如果列是字符串类型,传入条件是必须用引号引起来,不然...
    select * from tb1 where name = 999;(不走索引)
- !=
    select * from tb1 where name != alex;(查询时不走索引)
    特别的:如果是主键,则还是会走索引
        select * from tb1 where nid != 123;(查询时走索引)
- >
    select * from tb1 where name > alex; (‘>’中普通索引查询时不走索引)
    特别的:如果是主键或索引是整数类型,则还是会走索引
        select * from tb1 where nid > 123; (查询时走索引)
        select * from tb1 where num > 123
- order by
    当根据索引排序时候,选择的映射如果不是索引,则不走索引;选择的映射如果是索引,则走索引
    select email from tb1 order by name desc;  (查询时不走索引)
    select name from tb1 order by name desc;    (查询时走索引)
    特别的:如果对主键排序,则还是走索引:
        select * from tb1 order by nid desc;
 
- 组合索引最左前缀
    如果组合索引为:(name,email,pwd)
    name and email       -- 使用索引
    name                 -- 使用索引
    email                -- 不使用索引
    email and pwd   --不使用索引

 

索引的其它注意事项

- 避免使用select *
- count(1)或count(列) 代替 count(*)
- 创建表时尽量时 char 代替 varchar
- 表的字段顺序固定长度的字段优先(即将定长的放前面,不定长的后放)
- 组合索引代替多个单列索引(经常使用多个条件查询时)
- 尽量使用短索引
--指定列的前几个字符创建索引
--qwer99999
--sdfg99999
--askj99999(指定列的前4个字符创建索引)
- 使用连接(JOIN)来代替子查询(Sub-Queries) - 连表时注意条件类型需一致 - 索引散列值(重复少)不适合建索引,例:性别不适合

 

limit分页

 无论是否有索引,limit分页是一个值得关注的问题;

limit会去数据表扫m+n行数据;如果使用where nid>p,则会直接跳过前p行,然后从p行开始往下扫行;limit最好使用这种方式。

 

慢日志查询

1.配置mysql自动记录慢日志

slow_query_log = ON                            是否开启慢日志记录(默认值是off)
long_query_time = 2                              时间限制,超过此时间,则记录
slow_query_log_file = /usr/slow.log        日志文件
log_queries_not_using_indexes = ON     为使用索引的搜索是否记录(默认值是off)

 

注:查看当前配置信息:
       show variables like ‘%query%‘
     修改当前配置:直接修改内存中的值,立即生效,重启后将还原
    set global 变量名 = 值

建议:修改内存和配置文件中的值,这样就无需重启服务

2.查看mysql慢日志 

mysqldumpslow -s at -a  /usr/local/var/mysql/MacBook-Pro-3-slow.log

 

技术分享图片
"""
--verbose    版本
--debug      调试
--help       帮助
 
-v           版本
-d           调试模式
-s ORDER     排序方式
             what to sort by (al, at, ar, c, l, r, t), ‘at‘ is default
              al: average lock time
              ar: average rows sent
              at: average query time
               c: count
               l: lock time
               r: rows sent
               t: query time
-r           反转顺序,默认文件倒序拍。reverse the sort order (largest last instead of first)
-t NUM       显示前N条just show the top n queries
-a           不要将SQL中数字转换成N,字符串转换成S。don‘t abstract all numbers to N and strings to ‘S‘
-n NUM       abstract numbers with at least n digits within names
-g PATTERN   正则匹配;grep: only consider stmts that include this string
-h HOSTNAME  mysql机器名或者IP;hostname of db server for *-slow.log filename (can be wildcard),
             default is ‘*‘, i.e. match all
-i NAME      name of server instance (if using mysql.server startup script)
-l           总时间中不减去锁定时间;don‘t subtract lock time from total time
"""
View Code

 

  

其它

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 ;
if条件语句

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 ;
while循环

 

技术分享图片
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 ;
repeat循环

 

技术分享图片
BEGIN
    
    declare i int default 0;
    loop_label: loop
        
        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
loop

3.动态执行sql语句

技术分享图片
delimiter \DROP PROCEDURE IF EXISTS proc_sql \CREATE PROCEDURE proc_sql ()
BEGIN
    declare p1 int;
    set p1 = 11;
    set @p1 = p1;

    PREPARE prod FROM select * from tb2 where nid > ?;  #mysql中的占位符是‘?’
    EXECUTE prod USING @p1;  #做字符串格式化即nid>11,这里的变量必须要有@号,否则会报错,目的是防止sql注入
    DEALLOCATE prepare prod; 

END\delimiter ;
动态执行sql

 

MySQL(2)

标签:状态   cti   原则   动态   第一个   锁定   优化   字典   映射   

原文地址:https://www.cnblogs.com/lriwu/p/8480006.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!