zoukankan      html  css  js  c++  java
  • MySQL 之 数据库终篇

    一、函数

      函数有两类,一类是 Mysql 的内置函数,一类是 自定义函数。

      1.1 内置函数

       部分内置函数

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

      1.2 自定义函数

       1.2.1 创建函数

     1 delimiter \
     2 create function f1(
     3     i1 int,
     4     i2 int)
     5 returns int
     6 BEGIN
     7     declare num int;
     8     set num = i1 + i2;
     9     return(num);
    10 END \
    11 delimiter ;
    View Code

       1.2.2 删除函数

       drop function func_name;

       1.2.3 执行函数

    1 # 获取返回值
    2 declare @i VARCHAR(32);
    3 select UPPER('alex') into @i;
    4 SELECT @i;
    5 
    6 
    7 # 在查询中使用
    8 select f1(11,nid) ,name from tb2;
    View Code

      1.3 存储过程和函数的区别

      存储过程:

        内部执行 sql 语句

        intout ,out 构造返回值

        call : 存储过程名称

      函数:

        内部不允许 sql 语句 但是 允许如下类型语句

       (select nid into a from student where name='liufeiduo') 它是赋值语句 把查询到的 nid 赋值 给了 变量 a

        return 返回

        select 函数名(参数)

    二、索引

      2.1 功能:

        - 约束

          - 主键

          - 外键

          - 唯一

          - 普通

          - 组合

        - 加速查找

      2.2 索引为什么可以加速查找?

        用到了 B - tree 结构进行查找,多路搜索树 所以速度比较快。

      2.3 索引的种类

        ① 普通索引  -- 加速查找

        ② 唯一索引  -- 加速查找,约束列数据不能重复,可以为 Null 

        ③ 主键索引  -- 加速查找,约束列数据不能重复,不能为 Null

        ④ 组合索引  -- 多列可以创建一个索引文件

      2.4 普通索引

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

    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 )
    创建 表 + 索引
    1 create index index_name on table_name(column_name)
    创建 索引
    1 drop index_name on table_name;
    删除 索引
    1 show index from table_name;
    查看 索引

      2.5 唯一索引

       唯一索引有两个功能:加速查询 和 唯一约束(可含null)

    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     unique ix_name (name)
    7 )
    创建表 + 索引
    1 create unique index 索引名 on 表名(列名)
    创建 唯一索引
    1 drop unique index 索引名 on 表名
    删除 唯一索引

      2.6 主键索引

       主键有两个功能:加速查询 和 唯一约束(不可含null)

     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 )
     8 
     9 OR
    10 
    11 create table in1(
    12     nid int not null auto_increment,
    13     name varchar(32) not null,
    14     email varchar(64) not null,
    15     extra text,
    16     primary key(nid),
    17     index ix_name (name)
    创建表 + 索引
    1 alter table 表名 add primary key(列名);
    创建主键索引
    1 alter table 表名 drop primary key;
    2 alter table 表名  modify  列名 int, drop primary key;
    删除 主键索引

      2.7 组合索引

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

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

    1 create index ix_name_email on in3(name,email);
    创建 组合索引

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

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

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

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

      2.8 覆盖索引

       应用了索引,并且不用到数据表中去查询数据的情况 叫 覆盖索引,只需要在索引表中就能获取到数据时。

      2.9 合并索引

       把两个索引合并起来进行搜索,是两个单独的索引文件,区别于组合索引。组合合并索引取舍要由业务需求来决定,就优化来说,组合索引优化效果更好一点,但有短板。

    三、执行计划

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

      3.1 语法

        explain select * from 表名;

        当 type 里面出现 ALL 和 INDEX 的情况下,一般效率不高。

        type : ALL 全表扫描  type:INDEX 全索引表扫描

      3.2 limit 优化

        select * from tb1 where email='123';       select * from tb1 where email='123' limit 1; 

        前者没有后者效率高,后者当找到时便不会继续寻找了,效率有所提升。

        当 SQL:ALL、INDEX 都是有优化余地的,对表结构进行优化。

      3.3 range 

        当对索引列进行扫描时,类型是 range ,当对不是索引列进行扫描的时候,类型是 ALL,进行的全表扫描。

        range 效率要比上方两个高。  注意:!= 和 >

     1     id
     2         查询顺序标识
     3             如:mysql> explain select * from (select nid,name from tb1 where nid < 10) as B;
     4             +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
     5             | id | select_type | table      | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
     6             +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
     7             |  1 | PRIMARY     | <derived2> | ALL   | NULL          | NULL    | NULL    | NULL |    9 | NULL        |
     8             |  2 | DERIVED     | tb1        | range | PRIMARY       | PRIMARY | 8       | NULL |    9 | Using where |
     9             +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
    10         特别的:如果使用union连接气值可能为null
    11 
    12 
    13     select_type
    14         查询类型
    15             SIMPLE          简单查询
    16             PRIMARY         最外层查询
    17             SUBQUERY        映射为子查询
    18             DERIVED         子查询
    19             UNION           联合
    20             UNION RESULT    使用联合的结果
    21             ...
    22     table
    23         正在访问的表名
    24 
    25 
    26     type
    27         查询时的访问方式,性能:all < index < range < index_merge < ref_or_null < ref < eq_ref < system/const
    28             ALL             全表扫描,对于数据表从头到尾找一遍
    29                             select * from tb1;
    30                             特别的:如果有limit限制,则找到之后就不在继续向下扫描
    31                                    select * from tb1 where email = 'seven@live.com'
    32                                    select * from tb1 where email = 'seven@live.com' limit 1;
    33                                    虽然上述两个语句都会进行全表扫描,第二句使用了limit,则找到一个后就不再继续扫描。
    34 
    35             INDEX           全索引扫描,对索引从头到尾找一遍
    36                             select nid from tb1;
    37 
    38             RANGE          对索引列进行范围查找
    39                             select *  from tb1 where name < 'alex';
    40                             PS:
    41                                 between and
    42                                 in
    43                                 >   >=  <   <=  操作
    44                                 注意:!=> 符号
    45 
    46 
    47             INDEX_MERGE     合并索引,使用多个单列索引搜索
    48                             select *  from tb1 where name = 'alex' or nid in (11,22,33);
    49 
    50             REF             根据索引查找一个或多个值
    51                             select *  from tb1 where name = 'seven';
    52 
    53             EQ_REF          连接时使用primary key 或 unique类型
    54                             select tb2.nid,tb1.name from tb2 left join tb1 on tb2.nid = tb1.nid;
    55 
    56 
    57 
    58             CONST           常量
    59                             表最多有一个匹配行,因为仅有一行,在这行的列值可被优化器剩余部分认为是常数,const表很快,因为它们只读取一次。
    60                             select nid from tb1 where nid = 2 ;
    61 
    62             SYSTEM          系统
    63                             表仅有一行(=系统表)。这是const联接类型的一个特例。
    64                             select * from (select nid from tb1 where nid = 1) as A;
    65     possible_keys
    66         可能使用的索引
    67 
    68     key
    69         真实使用的
    70 
    71     key_len
    72         MySQL中使用索引字节长度
    73 
    74     rows
    75         mysql估计为了找到所需的行而要读取的行数 ------ 只是预估值
    76 
    77     extra
    78         该列包含MySQL解决查询的详细信息
    79         “Using index80             此值表示mysql将使用覆盖索引,以避免访问表。不要把覆盖索引和index访问类型弄混了。
    81         “Using where82             这意味着mysql服务器将在存储引擎检索行后再进行过滤,许多where条件里涉及索引中的列,当(并且如果)它读取索引时,就能被存储引擎检验,因此不是所有带where子句的查询都会显示“Using where”。有时“Using where”的出现就是一个暗示:查询可受益于不同的索引。
    83         “Using temporary84             这意味着mysql在对查询结果排序时会使用一个临时表。
    85         “Using filesort”
    86             这意味着mysql会对结果使用一个外部索引排序,而不是按索引次序从表里读取行。mysql有两种文件排序算法,这两种排序方式都可以在内存或者磁盘上完成,explain不会告诉你mysql将使用哪一种文件排序,也不会告诉你排序会在内存里还是磁盘上完成。
    87         “Range checked for each record(index map: N)”
    88             这个意味着没有好用的索引,新的索引将在联接的每一行上重新估算,N是显示在possible_keys列中索引的位图,并且是冗余的。
    详细补充

      3.4 如何正确使用索引

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

       即使建立索引,索引也不会生效:

     1 - like '%xx'
     2     select * from tb1 where name like '%cn';
     3 - 使用函数
     4     select * from tb1 where reverse(name) = 'wupeiqi';
     5 - or
     6     select * from tb1 where nid = 1 or email = 'seven@live.com';
     7     特别的:当or条件中有未建立索引的列才失效,以下会走索引
     8             select * from tb1 where nid = 1 or name = 'seven';
     9             select * from tb1 where nid = 1 or email = 'seven@live.com' and name = 'alex'
    10 - 类型不一致
    11     如果列是字符串类型,传入条件是必须用引号引起来,不然...
    12     select * from tb1 where name = 999;
    13 - !=
    14     select * from tb1 where name != 'alex'
    15     特别的:如果是主键,则还是会走索引
    16         select * from tb1 where nid != 123
    17 - >
    18     select * from tb1 where name > 'alex'
    19     特别的:如果是主键或索引是整数类型,则还是会走索引
    20         select * from tb1 where nid > 123
    21         select * from tb1 where num > 123
    22 - order by
    23     select email from tb1 order by name desc;
    24     当根据索引排序时候,选择的映射如果不是索引,则不走索引
    25     特别的:如果对主键排序,则还是走索引:
    26         select * from tb1 order by nid desc;
    27  
    28 - 组合索引最左前缀
    29     如果组合索引为:(name,email)
    30     name and email       -- 使用索引
    31     name                 -- 使用索引
    32     email                -- 不使用索引
    View Code

       3.5 其它注意事项

    1 - 避免使用select *
    2 - count(1)或count(列) 代替 count(*)
    3 - 创建表时尽量时 char 代替 varchar
    4 - 表的字段顺序固定长度的字段优先
    5 - 组合索引代替多个单列索引(经常使用多个条件查询时)
    6 - 尽量使用短索引
    7 - 使用连接(JOIN)来代替子查询(Sub-Queries)
    8 - 连表时注意条件类型需一致
    9 - 索引散列值(重复少)不适合建索引,例:性别不适合

    四、分页

      limit 分页问题也是一个需要关注效率的问题。

     1 每页显示10条:
     2 当前 118 120125
     3 
     4 倒序:
     5             大      小
     6             980    970  7 6  6 5  54  43  32
     7 
     8 21 19 98     
     9 下一页:
    10 
    11     select 
    12         * 
    13     from 
    14         tb1 
    15     where 
    16         nid < (select nid from (select nid from tb1 where nid < 当前页最小值 order by nid desc limit 每页数据 *【页码-当前页】) A order by A.nid asc limit 1)  
    17     order by 
    18         nid desc 
    19     limit 10;
    20 
    21 
    22 
    23     select 
    24         * 
    25     from 
    26         tb1 
    27     where 
    28         nid < (select nid from (select nid from tb1 where nid < 970  order by nid desc limit 40) A order by A.nid asc limit 1)  
    29     order by 
    30         nid desc 
    31     limit 10;
    32 
    33 
    34 上一页:
    35 
    36     select 
    37         * 
    38     from 
    39         tb1 
    40     where 
    41         nid < (select nid from (select nid from tb1 where nid > 当前页最大值 order by nid asc limit 每页数据 *【当前页-页码】) A order by A.nid asc limit 1)  
    42     order by 
    43         nid desc 
    44     limit 10;
    45 
    46 
    47     select 
    48         * 
    49     from 
    50         tb1 
    51     where 
    52         nid < (select nid from (select nid from tb1 where nid > 980 order by nid asc limit 20) A order by A.nid desc limit 1)  
    53     order by 
    54         nid desc 
    55     limit 10;
    View Code

    五、慢日志

      5.1 配置慢日志文件

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

      注:查看当前配置信息:
             show variables like '%query%'
           修改当前配置:
          set global 变量名 = 值

      5.2 查看MySQL慢日志

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

    六、总结

      索引是未来必然会用到的以及面试的重点!深究一下索引!

  • 相关阅读:
    Cortex-M3 跳转到指定bin执行
    Keil生成汇编文件、bin文件
    鲁迅
    Cortex-M3的一些概念
    linux下tar.gz、tar、bz2、zip等解压缩、压缩命令小结【转】
    c/c++ linux下 移动、删除文件
    c/c++ linux下 获取时间戳
    c++ 生成随机字符串【转】
    c++ <fstream> 读写文件总结
    c++11 std::mutex
  • 原文地址:https://www.cnblogs.com/jinzejun/p/9350525.html
Copyright © 2011-2022 走看看