• 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、下一页
    ')
        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:MySQLmysql-5.6.48-winx64my.ini
    mysqld --default-files = C:MySQLmysql-5.6.48-winx64my.ini
    
    /* (1) 重新设置完成后需要进行重启程序生效 */
    指定:
    slow_query_log = ON (默认值OFF,在内存里面)                /* 开启慢日志记录 */
    log_queries_not_using_indexes = ON (默认值OFF,在内存里面) /* 为使用索引的搜索记录 */
    long_query_time = 2                                      /*时间限制,超过2s,则记录 */
    slow_query_log_file = C:MySQLslow.log                  /* 日志文件储存 */
    
    /* (2) 在内存中直接修改,仅限这次使用 */
    slow_query_log = OFF
    log_queries_not_using_indexes = OFF
    long_query_time = 2
    slow_query_log_file = C:MySQLslow.log

    注意:

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

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

    查看MySQL慢日志

    mysqldumpslow -s at -a  C:MySQLslow.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
  • 相关阅读:
    【Codeforces】【161Div2】
    【ZOJ月赛】【树形DP】【I.Destroy】
    【Baltic 2001远程通信】
    【树形DP】【分组背包】【HDU1561】
    【差分约束系统】【仍未AC】【Asia Harbin 2010/2011】【THE MATRIX PROBLEM】
    【DP】【2012 ACM/ICPC 成都赛区现场赛】【I.Count】
    【ZOJ月赛】【二分查找】【A.Edward's Cola Plan】
    【DP】【单调队列多重背包】
    【树形依赖背包】
    SQL 格式
  • 原文地址:https://www.cnblogs.com/chungzhao/p/13169904.html
Copyright © 2020-2023  润新知