• 高性能mysql 4 ,5章


    第4章

    1:查询优化,多表连接时只取需要的列,要对select * 保持怀疑。

    2:如果发现访问的数据行数很大,而生成的结果中数据行很少,那么可以尝试更复杂的修改

         a: 使用覆盖索引,b: 更改架构,一个例子就是使用汇总表 ,c: 重写复杂的查询,让mysql的优化器可以以优化的方式执行它。

    3:重构查询的方式,a: 将复杂查询修改为多个简单查询,b:  缩短查询,使用分治算法,每次查询,删除一部分。c:分解联接,可以把一个多表联接分解成多个单个查询,然后在应用程序端,实现联接操作。

    单个查询使用缓存效率更高,应用程序端进行连接可以更方便的扩展数据库,把不同的表放在不同的服务器上面。

    4:什么时候再应用程序端进行联接效率更高

    a: 可以缓存早期查询的大量数据,b:使用了多个MyISAM表(单个查询锁住表的时间更短),c: 数据分布在不同的服务器上,d: 对于大表使用in()替换联接  e:一个联接引用了同一个表很多次

    5:查询状态,每个mysql连接都有装态,可以用show full processlist;来查询,在Command列。

    mysql> show full processlist;
    +----+------+-----------------+------+---------+------+-------+-----------------------+
    | Id | User | Host            | db   | Command | Time | State | Info                  |
    +----+------+-----------------+------+---------+------+-------+-----------------------+
    |  7 | root | localhost:51849 | NULL | Sleep   |   44 |       | NULL                  |
    |  8 | root | localhost:51855 | test | Sleep   |   21 |       | NULL                  |
    |  9 | root | localhost:51857 | test | Query   |    0 | NULL  | show full processlist |
    +----+------+-----------------+------+---------+------+-------+-----------------------+
    3 rows in set

     6: 选择无缓存的查询

    select sql_no_cache count(*) from salarie;

     7:优化过程

        a: 对联接中的表重新排序  b:将外联接转换成内联接    c: 代数等价法则 : 例如  a=5 and a>5会被精简成 a>5

        d:  优化min,max,count :  min索引B+树的左边就行了,max查找索引的最右边就行了。  如果where后面没有条件,MyISAM总是保留行数的精确值

         e: 计算和减少常量表达式:例如min函数可以被简化成为一个常量。    f:覆盖索引:当索引包含查询需要的所有列时,可以使用覆盖索引。

    g:子查询优化:mysql可以将某些类型的子查询转换成相等的效率更高的形式,把它们简化为索引查找,而不是独立的多个查询。     有子查询时, 先子查询再外查询。

    h: 早期终结  i:相等传递    j: 比较in()里面的数据   k: 表和索引统计   l:  mysql的联接执行策略    

    8: mysql查询优化器的限制

       a: 关联子查询:会出现意想不到的优化结果。有可能慢,有可能快,要根据实际测试结果。  b: 联合的限制   c:索引合并优化  d:......

    9: limit 和  offset的优化,  有时候可以将limit转换为位置性查询,例如  p between 50 and 54 order by postion;

    mysql> select * from salarie limit 4 offset 9;
    +--------+--------+----+
    | name   | salary | id |
    +--------+--------+----+
    | wangwu |    200 | 10 |
    | wangwu |    200 | 11 |
    | wangwu |    200 | 12 |
    | wangwu |    200 | 13 |
    +--------+--------+----+
    4 rows in set

    10:   查询优化提示:

    a:straight_join  可以用于联接语句。

    select straight_join * from salarie;

    b: high_priority 指定查询语句的优先级

    select high_priority * from salarie;

    c: delayed ,INSERT DELAYED仅适用于MyISAM, MEMORY和ARCHIVE表。延迟插入。

    insert into delayed salarie(name,salary) values('gaodan',4000);

     11:  INTERVAL  指定时间区间,http://www.w3school.com.cn/sql/func_date_add.asp

       12: 用户自定义变量

    set @var1:=0;

    第5章  mysql高级特性

    1:缓存就是一个查找表。

    2:缓存不会存储有不确定结果的查询,例如now(),current_date();

    3: 当事务内部的语句更改了表,即使innodb的多版本机制应当对其他语句隐藏事务的变化,服务器也会使所有引用了该表的查询缓存失效,直到事务提交之前,该表会全局的不可缓存。

     4:缓存未命中:缓存未命中的原因可能有以下几个原因,a: 查询不可缓存:原因可能是含有不可确定函数,比如current_date,也有可能是缓存结果太大无法缓存。

    状态变量Qchache_not_cached会因为这两种无法缓存的查询而增加。

    b:服务器以前没有见过这个缓存,所以它根本就没有机会缓存自身结果。

    c:查询的缓存以前被缓存过,但是服务器把它移除了,发生移除的原因可能是内存空间不够,所以被人从服务器把它溢出了,也可能缓存失效了。

    如果服务器很多缓存未命中,但是不能缓存的查询却很少,那么原因应该是下面之一:

    a:查询缓存未被激活,也就是说服务器根本没有机会将结果存储到缓存中

    b: 服务器看到了以前从未见过的缓存,如果没有很多重复的查询,即使缓存被激活了,也有可能见到这种情况。

    c:很多缓存失效。

     5:如果服务器实际使用的缓存数量小于分配的内存,那么应该把分配给它的内存减少一点,如果由于内存限制引起了缓存失效,那么就应该多分配一些内存。

     6:对查询缓存进行维护与调优,可以通过以下选项设置

    Query_cache_type=OFF/ON/DEMAND 表示缓存是否被激活
    Query_cache_size 分配给查询的总内存,以字节为单位,必须是1024的整数倍。
    Query_cache_min_res_unit 分配给缓存块的最小值
    Query_cache_limit 这个选项限制了mysql存储的最大结果
    Query_cache_wlock_invalidate 这个选项指是否缓存其他联接已经锁定的表。

    7:在查询中添加 SQL_CACHE 和SQL_NO_CACHE可以决定该查询是否使用缓存。  

    8:过程,函数

    存储过程

    delimiter //
    drop procedure if exists p1;//
    create procedure p1(in i int)
        begin
        declare ii int default 0;
        set ii=i;
            while i<10 do
                insert into salarie(name,salary) values('shunzi',1000);
                set ii=ii+1;
            end while;
        end;//
        delimiter;

     触发器,同一张表上不能创建两个触发器 ,同时创建两个触发器,会提示一下错误。

    1235 - This version of MySQL doesn't yet support 'multiple triggers with the same action time and event for one table'
    mysql> delimiter //
    drop trigger if exists t1; //
    create trigger t1 before insert on t
    for each row
    begin
        if(new.id>10000) then
            set new.id=10000;
        end if;
    end;//
    delimiter;
    Query OK, 0 rows affected
    
    Query OK, 0 rows affected
    
    mysql> insert into t values(10005);
    Query OK, 1 row affected
    
    mysql> select * from t;
    +-------+
    | id    |
    +-------+
    | 10000 |
    +-------+
    1 row in set

     事件:事件类似于定时任务,会在特定时间执行一次预先设定好的sql代码。时间和线程无关,它云星于一个独立的定时器线程上。

    事件的执行:https://blog.csdn.net/lixia755324/article/details/53923856   https://blog.csdn.net/u013421629/article/details/72846742

     例如定义一个事件,每周调用一下存储过程p1

    create event e1 on schedule every 1 week
    do
    call p1(10);

    查看information_schema_events 表可以了解事件的状态

    创建一个事件e2,  每两周优化一次 表somedb

    create event t2 on schedule every 2 week
    do 
    begin
        declare continue handler for sqlexception
            begin end;
        if get_lock('somedb',0) then   -- 加锁
            do call optimize_tables('somedb');
        end if;
        do release_lock('somedb');
            
    end

    事件:自定义事件liyafei

    delimiter //
    drop event if exists e3;//
    create event e3 on schedule every 1 second on completion preserve
    do
    begin
        insert into t values(3);
    end;//
    delimiter;
    
    alter event e3 enable;

    9:注释:可以使用/**/给代码加注释,使用!9990给该注释一个版本号,例如下面在触发器中加注释。

    //触发器
    delimiter //
    drop trigger if exists t1; //
    create trigger t1 before insert on t
    for each row
    begin
    /* !9999
    hello;
    */
        if(new.id>10000) then
            set new.id=10000;
        end if;
    end;//
    delimiter;

     10:  函数处理  当not found时,将a设置为0

    declare continue/exit HANDLER FOR NOT FOUND set a=0;

     11:游标 https://www.cnblogs.com/liyafei/p/9443464.html

    12:准备语句

    使用增强的二进制客户端/服务器协议在客户端和服务器之间高效的发送数据。创建准备语句时,客户端库会向服务器发送一个实际查询的原型,然后服务器对该原型进行解析和处理,将部分优化过的原型保存起来,并且给客户端返回一个状态句柄。客户端可以通过定义状态句柄重复地进行查询。

    准备语句的优点:
    a:服务器只需要解析一次查询,这节约了解析和其他的开销
    b: 因为服务器缓存了一部分执行计划,所以它只需要执行某些优化步骤一次。
    c: 通过二进制发送参数比通过ascll码要快的多
    d: 整个查询不会被发送到服务器,只有参数才会被发送,这减少了网络流量
    e: mysql 直接把参数保存在服务器的缓冲区内,不需要在内存中到处拷贝。
    准备查询语句不需要在应用程序中对值进行转义和加引号,防止了攻击。

    -- 准备语句可以有参数,

    insert into salarie(id,name,salary) values(?,?,?);

     -- 准备语句的SQL语言接口

    mysql> set @sql:='select id,salary,name from salarie where id=?';
    prepare pre_stmt_fetch from @sql;   --  提取出准备语句
    set @actor_name:='20';             -- 参数值
    execute pre_stmt_fetch using @actor_name; -- 执行 
    Query OK, 0 rows affected
    
    Query OK, 0 rows affected
    Statement prepared
    
    Query OK, 0 rows affected
    
    +----+--------+----------+
    | id | salary | name     |
    +----+--------+----------+
    | 20 |    400 | zhangsan |
    +----+--------+----------+
    1 row in set

     -- 删除准备语句

    mysql> deallocate prepare pre_stmt_fetch;
    Query OK, 0 rows affected
    准备语句主要用于存储过程,可以在存储过程内部执行动态sql。
    例如:下面是一个可以在特定的数据库中针对每一个表都调用OPTIMIZE TABLE;
    drop procedure if exists oprimize_tables;
    DELIMITER //
    create procedure oprimize_tables(db_name varchar(64))
        BEGIN
            declare t varchar(64);
            declare done int default 0;
            declare c cursor for 
                select table_name from information_schema_.tables where table_schema=db_name and table_type='base table';
            declare continue handler for sqlstate '02000' set done=1;
            open c;
            tables_loop:LOOP
                fetch c into t;
                if done then
                    close c;
                    leave tables_loop;
                end if;
                set @stmt_text:=concat("OPTIMIZE TABLE",db_name,".",t);
                prepare stmt from @stmt_text;
                execute stmt;
                deallocate prepare stmt;
            end LOOP;
            close c;
        END//
    DELIMITER;

     13:视图

        可更新视图:可更新视图应该满足下列所有条件

    a: from字句中只有一个数据库关系

    b: select 字句中只包含关系的属性名,不包含任何表达式,聚集或distinct声明。

    c: 任何没有出现在select字句中的属性可以取空值;即这些属性行没有 not null约束,也不构成主码的一部分

    d: 查询中不含有group by 或having字句。

    14:视图的性能影响:

    a:可以改善性能,例如,利用视图重构数据库架构的某一阶段,可以在更改它访问的表的同时,使代码继续工作。

    b: 可以使用视图实现列权限,但是却没有实际创建这些权限的开销

    create view v1 as select salary,name from salarie;
    grant select on v1.* to user1;

    视图的局限:

    a:mysql不支持物化视图,物化视图通常把结果存储在一个不可见的表里面,然后周期性的从原始数据对不可见的表进行刷新。

    b: mysql 也不支持索引视图,  可以通过创建缓存表和汇总表模拟物化视图和索引视图。

    15:字符集和排序规则  https://www.cnblogs.com/wcwen1990/p/6917109.html

    a:为什么不都用utf-8,  因为utf-8 占用的字节比较大。

    b:

    16:全文搜索

    a: myisam全文索引是一种特殊的具有两层结构的B树,第一层保存了关键字,然后对每个关键字,第二层包含了一个列表,它有相关的文档指针组成,这些指针包含该关键字的全文集合。

    b:查询索引

    mysql> show index from salarie;
    +---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    | Table   | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
    +---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    | salarie |          0 | id       |            1 | id          | A         |          27 | NULL     | NULL   |      | BTREE      |         |               |
    +---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    1 row in set

    17:合并表和分区表

    合并表:

    drop table t1;
    drop table t2;
    drop table mrg;
    create table t1(a int)engine=MyISAM;
    create table t2(a int)engine=MyISAM;
    insert into t1 values(1),(2);
    insert into t2 values(1),(2);
    create table mrg(a int) engine=merge union(t1,t2) insert_method=last;
    select * from mrg;

    报错

    1168 - Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist

    是因为merge默认引擎没写:修改如下

    create table mrg(a int) engine=merge union(t1,t2) insert_method=last default charset=utf8;

    结果:

    mysql> drop table t1;
    drop table t2;
    drop table mrg;
    create table t1(a int)engine=MyISAM;
    create table t2(a int)engine=MyISAM;
    insert into t1 values(1),(2);
    insert into t2 values(1),(2);
    create table mrg(a int) engine=merge union(t1,t2) insert_method=last default charset=utf8;
    select * from mrg;
    
    Query OK, 0 rows affected
    
    +---+
    | a |
    +---+
    | 1 |
    | 2 |
    | 1 |
    | 2 |
    +---+
    4 rows in set

    在合并表中插入,能够在指标中查询到

    mysql> insert into mrg values(3);
    Query OK, 1 row affected
    
    mysql> select * from t2;
    +---+
    | a |
    +---+
    | 1 |
    | 2 |
    | 3 |
    +---+
    3 rows in set

    分区表:

    分区表,可以按照日期分区,如果一个表很大,例如每天插入10000000条记录,时间长了,表中数据原来越大,使用主键全表扫面,性能较低。

    于是,可以按日期对表进行分区,每次查询访问某个时间段即可。

    但是不要同时加上主键和对表进行分区,这有可能降低性能。尤其是要对所有分区进行扫描的时候,在考虑分区时,要仔细地做性能评测,因为分区表并不总是能提高性能。

    分区表使用和示例:

     创建一个表,对其分区

    create table sales_by_day(
        day date not null,
        product int not null,
        sales decimal(10,2) not null,
        returns decimal(10,2) not null,
        primary key(day,product)
    )engine=innodb;
    
    
    alter tables sales_by_day partition by range(year(day))(
        partition p_2006 values less than (2007),
        partition p_2007 values less than (2008),
        partition p_2008 values less than (2009),
        partition p_catchall values less than maxvalue);
        
    insert into sales_by_day(day,product,sales,returns) values
    ('2007-01-15',19,50.00,52.00),
    ('2008-01-15',11,41.00,42.00);

     分区表一个常用的用途就是分布大表中的行。

    alter table very_big_table partition by key(<primary key columns>)(
    partition p0 data direcotry='/data/mydb/big_table_p0',
    partition p1 data direcotry='/data/mydb/big_table_p1'
    );
  • 相关阅读:
    PHP 函数
    MariaDB——(三) MariaDB 10.0.15 standard replication主从复制搭建
    MariaDB——(二) MariaDB 10.0.15 日志文件—undo 日志
    MariaDB——(一)CentOS 6.5 下 MariaDB 10.0.15 YUM 安装
    虚拟机中的linux系统文件突然全部变成只读的问题
    复制虚拟机vmware centos搭建集群节点过程中网络配置eth0和eth1遇到的问题以及NAT模式下虚拟机静态IP配置方法
    WMware 中CentOS系统Hadoop 分布式环境搭建(一)——Hadoop安装环境准备
    关于Oracle字符集在dmp文件导入导出中的乱码影响
    VMware 打开虚拟机的时候提示 internal error 内部错误 遇到这个问题时我的解决方法
    ORACLE 存储过程中保存用户自定义异常信息的一种方式
  • 原文地址:https://www.cnblogs.com/liyafei/p/9536630.html
Copyright © 2020-2023  润新知