Python-Basis-25th

周日,晴,记录生活分享点滴

参考博客1:https://www.cnblogs.com/wupeiqi/articles/5713323.html

参考博客2:https://www.cnblogs.com/wupeiqi/articles/5716963.html

 

函数

部分内置函数

CHAR_LENGTH(str)  /* 获取字符的长度 */
    返回值为字符串str 的长度,长度的单位为字符。一个多字节字符算作一个单字符。
    对于一个包含五个二字节字符集, LENGTH()返回值为 10, 而CHAR_LENGTH()的返回值为5。

CONCAT(str1,str2,...)  /* 字符串拼接 */
    如有任何一个参数为NULL ,则返回值为 NULL。
CONCAT_WS(separator,str1,str2,...)  /* 字符串拼接(自定义连接符)separator指分隔符,在此处可自定义连接符 */
    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超过原字符串长度,则由新字符串完全替换
    例如:
        select insert('alex',2,2,'GDBX');
        指从第二个字母'l'起的两个字母'le'替换为'GDBX',虽然字符超多原字符长度,但输出结果为'aGDBXx'
INSTR(str,substr)
    返回字符串 str 中子字符串的第一个出现位置。

LEFT(str,len)  /* 获取前几个字符 */
    返回字符串str 从开始的len位置的子序列字符。

LOWER(str)  /* 变小写 */
    
UPPER(str)  /* 变大写 */

LTRIM(str)  /* 移除左边的空格,同python的strip */ 
    返回字符串 str ,其引导空格字符被删除。
RTRIM(str)  /* 移除右边的空格 */
    返回字符串 str ,结尾空格字符被删去。
SUBSTRING(str,pos,len)
    获取字符串子序列

LOCATE(substr,str,pos)
    获取子序列索引位置

REPEAT(str,count)
    返回一个由重复的字符串str 组成的字符串,字符串str的数目等于count 。
    若 count <= 0,则返回一个空字符串。
    若str 或 countNULL,则返回 NULLREPLACE(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'

自定义函数

delimiter \\
create function f1(
    i1 int,
    i2 int)
returns int
BEGIN
    /* 不能获取结果集 select * from tb1 */
    declare num int;
    set num = i1 + i2;
    return(num);
END \\
delimiter ;

/*
存储过程:
    sql语句
    inout,out构造返回值
    如何调用-->  call:存储过程名称
函数:
    sql不允许
    允许(通过sql语句通过sql查询一个值给某个变量进行赋值)
        declare a int;
        select nid into a from student where name = 'alex' -- nid:1  name:alex
        -- a = 1
    return返回
    如何调用-->  select 函数名(参数)
*/

删除函数

drop function func_name;

执行函数

/* 获取返回值 */
declare @i VARCHAR(32);
select UPPER('alex') into @i;
SELECT @i;

/* 在查询中使用 */
select f1(11,nid) ,name from tb2;

 

事务

delimiter \\
create PROCEDURE p1(
       OUT p_return_code tinyint
       )
       
       /* 如果存储过程出现异常,执行代码块一 */
       BEGIN
       DECLARE exit handler for sqlexception  /* 声明一个特殊的变量sqlexceptiono,表示执行了sql的异常处理 */
       BEGIN
           -- ERROR
           set p_return_code = 1;
           rollback;  /* 回滚,set p_return_code = 0;不再执行 */
       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;  /* START到COMMIT过程中的操作为一个事务操作,如果中间有一个出错,就回滚到原来的状态 */
       
       -- SUCCESS 
       set p_return_code = 0; 
       
       END\\
delimiter ;

 

索引·重要

普通索引

普通索引一个功能:加速查找

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)  /* 将name这一列创建了一个索引 */
)

2.创建索引

create index 索引名称 on 表(列名)

3.删除索引

drop index_name on table_name;

4.查看索引

show index from table_name;

唯一索引

唯一索引两个功能:加速查找 和 约束列数据不能重复,可为空null

是普通索引的一个特殊值

1.创建表 + 唯一索引

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)  /* 是普通索引的一个特殊值unique */
)

2.创建唯一索引

create unique index 索引名 on 表名(列名)

3.删除唯一索引

drop unique index 索引名 on 表名

主键索引

主键索引两个功能:加速查找 和 约束列数据不能重复,不能为空null

最强的索引,功能最多

1.创建表 + 创建主键

create table in1(
    nid int not null auto_increment primary key,  /* 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(nid),
    index ix_name (name)  /* 创建name普通索引 */
)

2.创建主键

alter table 表名 add primary key(列名);

3.删除主键

alter table 表名 drop primary key;
alter table 表名  modify  列名 int, drop primary key;

组合索引

组合索引一个功能:将n个列组合成一个索引(多列可以创建一个索引文件)

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

  • 普通组合索引:无约束

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

1.创建表

create table in3(
    nid int not null auto_increment primary key,
    name varchar(32) not null,
    email varchar(64) not null,
    extra text
)

2.创建组合索引

create index ix_name_email on in3(name,email);

3.查找:最左匹配

select * from tb1 where name = 'alex'  /* 使用索引 */
select * from tb1 where name = 'alex' and pwd = '123'  /* 使用索引 */
select * from tb1 where pwd = '123'  /* 不使用索引 */

如上创建组合索引之后,查询:

  • name and email -- 使用索引

  • name -- 使用索引

  • email -- 不使用索引

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


覆盖索引

select的数据列只需要在索引表中就能获取到数据时,并且不用去数据表中操作,叫覆盖索引

/* 普通索引 ---------------------------------- */
select * from tb where nid=1
    /* 先去索引中找,
       在去数据表找 */


/* 覆盖索引 ---------------------------------- */
select nid from tb where nid < 10
    /* 先去索引中找 */

合并索引

索引合并,使用多个单列索引组合搜索

nid name(单独索引) email(单独索引) pwd  /* 合并索引:两个索引文件 */

select * from tb where name='alex'
select * from tb where email='alex3714@163.com'
select * from tb where name='alex' or email='zhangsan@123.com'
nid name(组) email(合) pwd  /* 组合索引:一个索引文件 */
/* 最左前缀 */

select * from tb where name='alex'
select * from tb where email='alex3714@163.com' /* 根据最左前缀,无法使用索引 */
select * from tb where name='alex' or email='zhangsan@123.com'

组合索引和合并索引需要根据业务需求来决定

 

执行计划

相对比较准确表达出当前SQL运行状况

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

mysql> explain select * from tb2;
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
|  1 | SIMPLE      | tb2   | ALL  | NULL          | NULL | NULL    | NULL |    2 | NULL  |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
1 row in set (0.00 sec)
示例
1、explain SQL语句
    type:ALL    -- 全数据表扫描
    type:index  -- 全索引表扫描
    type:range  -- 范围索引扫描,效率高于ALL、index,特殊情况见详细
/* --------- SQL: ALL、Index 效率不高,都可优化 --------- */
        
2、limit
    select * from tb1 where email='123'  -- 全表扫描,没有limit 1 效率高
    select * from tb1 where email='123' limit 1;  -- 随机抽取一条进行扫描 

类型

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';
                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;
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


    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';
                            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列中索引的位图,并且是冗余的。
详细

 

如何命中索引

需要正确建立索引,否则索引不会生效:

- like '%xx'  /* %前有实体值走索引,没有实体值不走索引 */
    select * from tb1 where name like '%cn';
    
- 使用函数  /* 不要在查询条件上加函数,即使是索引,也无法使用,效率变低 */
    select * from tb1 where reverse(name) = 'wupeiqi';
    
- or
    select * from tb1 where nid = 1 or email = 'seven@live.com';
    特别的:当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;  /* 999与name类型不一致不走索引 */


/* 除了 != 、 > 其他的都走索引 */
- !=
    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 * from tb1 order by nid desc;
 
- 组合索引最左前缀
    如果组合索引为:(name,email)
    name and email       -- 使用索引
    name                 -- 使用索引
    email                -- 不使用索引

 

其他注意事项

  1. 避免使用select *

  2. count(1)或count(列) 代替 count(*)

  3. 创建表时尽量使 char 代替 varchar

  4. 表的字段顺序固定长度的字段优先,变长在后

  5. 组合索引代替多个单列索引(经常使用多个条件查询时) 两个在一起时,组合索引速度稍快于合并索引

  6. 尽量使用短索引(指定列前几个字符创建索引;text, blob 必须要执行长度)

  7. 使用连接(JOIN)来代替子查询(Sub-Queries)

  8. 连表时注意条件类型需一致

  9. 索引散列值(重复少)不适合建索引,例:性别不适合,就男女两个值,每个值里面还有其他很多值

 

分页

limit x, m :表x+m (越向后查询时间越慢)

where nid > 10000 直接跳过前10000条数,继续往下扫

def sqlexec(last_nid, is_next):
    import pymysql

    conn = pymysql.connect(host='192.168.12.29', port=3306, user='root', passwd='123', db='IndexDB', charset='utf8')
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    # 执行存储过程,获取存储过程的结果集,将返回值设置给了  @_存储过程名_序号 =
    if is_next:
        cursor.execute('select * from tb1 where nid>%s limit 10',last_nid)
        result = cursor.fetchall()
    else:
        cursor.execute('select * from tb1 where nid<%s order by nid desc limit 10', last_nid)
        result = cursor.fetchall()
        result = list(reversed(result))

    conn.commit()
    cursor.close()
    conn.close()
    return result

current_last_nid = 0
current__nid = 0
while True:
    p = input('1、上一页; 2、下一页\n')
    if p == '2':
        # 点击下一页
        is_next = True
        ret = sqlexec(current_last_nid, is_next)
    else:
        is_next = False
        ret = sqlexec(current_first_nid, is_next)
    current_first_nid = ret[0]['nid']
    current_last_nid = ret[-1]['nid']
    for i in ret:
        print(i)

 

慢日志查询

配置MySQL自动记录慢日志

方式一:在内存中直接修改


方式二:写一个配置文件  C:\MySQL\mysql-5.6.48-winx64\my.ini
mysqld --default-files = C:\MySQL\mysql-5.6.48-winx64\my.ini

/* (1) 重新设置完成后需要进行重启程序生效 */
指定:
slow_query_log = ON (默认值OFF,在内存里面)                /* 开启慢日志记录 */
log_queries_not_using_indexes = ON (默认值OFF,在内存里面) /* 为使用索引的搜索记录 */
long_query_time = 2                                      /*时间限制,超过2s,则记录 */
slow_query_log_file = C:\MySQL\slow.log                  /* 日志文件储存 */

/* (2) 在内存中直接修改,仅限这次使用 */
slow_query_log = OFF
log_queries_not_using_indexes = OFF
long_query_time = 2
slow_query_log_file = C:\MySQL\slow.log

注意:

  • 查看当前配置信息:show variables like '%query%'

  • 修改当前配置:set global 变量名 = 值

查看MySQL慢日志

mysqldumpslow -s at -a  C:\MySQL\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。do not 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           总时间中不减去锁定时间;do not subtract lock time from total time

 

posted @ 2020-06-21 23:34  ChungZhao  阅读(125)  评论(0编辑  收藏  举报