• 高性能Mysql


    show status like 'last_query_cost';   --  查询上次在mysql中查询的次数

    1: 根据前缀长度建立索引   https://www.cnblogs.com/gomysql/p/3628926.html

    根据整个长度city子段建立索引,然后统计各个前缀字符串出现的频率次数。

    mysql> update city_demo set city = ( select city from city order by rand() limit 1);
    Query OK, 1198 rows affected
    Rows matched: 1200  Changed: 1198  Warnings: 0
    
    mysql> select count(*) as cnt, city from city_demo group by city order by cnt desc limit 10;
    +-----+----------------------------+
    | cnt | city                       |
    +-----+----------------------------+
    |   7 | Nabereznyje Telny          |
    |   6 | Po                         |
    |   6 | Sousse                     |
    |   6 | Asuncin                    |
    |   6 | Sanaa                      |
    |   6 | Pudukkottai                |
    |   6 | Qalyub                     |
    |   5 | Acua                       |
    |   5 | San Felipe de Puerto Plata |
    |   5 | Pachuca de Soto            |
    +-----+----------------------------+
    10 rows in set
    
    -- 根据city子段 前3个字符 ,建立索引,统计前10个出现最多的索引字段 mysql
    > select count(*) as cnt,left(city,3) as pref from city_demo group by pref order by cnt desc limit 10; +-----+------+ | cnt | pref | +-----+------+ | 32 | San | | 15 | Tan | | 14 | Sou | | 10 | Cha | | 9 | Shi | | 9 | Kam | | 8 | Ash | | 8 | Hal | | 8 | Bra | | 8 | Vil | +-----+------+ 10 rows in set

    选择前6个字符作为前缀,建立索引,所得结果和将全部字段作为索引的结果一样。  也就是用6个字符作为索引和使用city字段全部内容作为索引,效果是一样的。

    mysql> select count(*) as cnt,left(city,6) as pref from city_demo group by pref order by cnt desc limit 10;
    +-----+--------+
    | cnt | pref   |
    +-----+--------+
    |   7 | San Fe |
    |   7 | Nabere |
    |   6 | Sanaa  |
    |   6 | Sousse |
    |   6 | Santa  |
    |   6 | Asunci |
    |   6 | Qalyub |
    |   6 | Pudukk |
    |   6 | Po     |
    |   5 | Xiangf |
    +-----+--------+
    10 rows in set

    前6个字符合全部字段的选择性,也很接近

    mysql> select count(distinct city)/count(*) as rate from city_demo;
    +--------+
    | rate   |
    +--------+
    | 0.4367 |
    +--------+
    1 row in set
    
    mysql> select count(distinct left(city,6))/count(*) as rate from city_demo;
    +--------+
    | rate   |
    +--------+
    | 0.4333 |
    +--------+
    1 row in set

     2:innodb  聚集索引

           聚集的意思是将键值和数据行保存在一起。

         innodb按照主键进行聚集,所以其它的辅助索引要引用主键去查询,主键不能过大。

        辅助索引,其叶子节点并不包含行记录的全部数据,叶子结点除了包含键值以外,每个叶子结点中的索引行还包含了一个书签,该书签用来告诉存储引擎可以在哪找到相应的数据行,由于   innodb引擎表是索引组织表,因此innodb存储引擎的辅助索引的书签就是相应行数据的聚集索引键

    3:压缩(前缀压缩)索引

       例如第一个值是'perform',第二个值是'performance',  第二个值就会被近似的存储为'7,ance'  。

    4:多余索引

    重复索引

         create table test(

            id int not null auto_increment primary key,  -- 创建了主键索引

            unique(id), -- 创建了索引

           index(id) --创建了索引

     )

    多余索引,A就创建了多余索引。

    create table test(
        A varchar(20),
        B varchar(20),
        index(A,B),
        index(A)
    )

     5:当某一个字段的域较少时,可以直接用in  来指定需要查询的字段

    select * from t1 where sex in ('male','female') and age>10;

     6:limit 10000,10将会抛弃很多查询到的值,会造成性能的损失,

    有时候如果可以使用书签记录上次取数据的位置,那么下次就可以直接从该书签记录的位置开始扫描,这样就可以避免使用OFFSET,比如下面的查询:

    SELECT id FROM t LIMIT 10000, 10;
    
    改为:
    SELECT id FROM t WHERE id > 10000 LIMIT 10;

    也可以只提取最终需要的行的主键列。然后把它在联接回去以取得所需要的列。这有助于最小化mysql必须进行的收集最终会丢掉的数据的工作。

    select salary from salaries inner join (select <primary key from_date> from salaries where x.emp_no=10001 order by salary limit 10,10) as x using(<primary key from_date>);
    -- using等价于join操作中的on,
    select salary from salaries inner join (select from_date from salaries where emp_no=10001 order by salary limit 10,10) x using(from_date);

     7:将大的查询缩短为很多小的查询,例如下面的删除语句,可以将一个大的删除语句改为每次删除1000个,防止长时间占用锁。

    delete from t1 where created<date_sub(now(),interval 3 month);
    -- 修改为
    set rows_affected=0;
    do{
       rows_affected=do_query("delete from t1 where created<date_sub(now(),interval 3 month) limit 10000");
      }while rows_affected>0

     8:查询一个最小值时,可以使用min函数,但是min函数会全表扫描。 此时如果索引为递增的,可以使用limit 1代替。

    select min(id) from t1;
    -- 替换为
    select id from t1 limit 1;

     9:查询表中 某些类型 的个数

    mysql> select name,count(*) from salarie group by name; 
    +----------+----------+
    | name     | count(*) |
    +----------+----------+
    | lisi     |        7 |
    | wangwu   |       11 |
    | zhangsan |        8 |
    | zhaoliu  |        1 |
    +----------+----------+
    4 rows in set
    
    mysql> select sum(if(name='wangwu',1,0)) as wangwu,sum(if(name='lisi',1,0)) as lisi from salarie;
    +--------+------+
    | wangwu | lisi |
    +--------+------+
    | 11     | 7    |
    +--------+------+
    1 row in set
    
    mysql> select count(name='wangwu' or null) as wangwu,count(name='lisi' or null) as lisi from salarie;
    +--------+------+
    | wangwu | lisi |
    +--------+------+
    |     11 |    7 |
    +--------+------+
    1 row in set
    
    mysql> 

     10:优化连接

            10.1  确保on或using使用的列上有索引, 一般在连接中的第二个表上建立索引即可。

             10.2  确保 group by 或order by只引用一个表中的列,这样mysql会尝试对这些操作使用索引。

     11:优化group by,   带有group by的连接可以将group by放到子查询中,会减少连接次数和查询次数。

    mysql> select s.id,s.name from salarie s inner join salarie using(name) group by(name);
    +----+----------+
    | id | name     |
    +----+----------+
    |  2 | lisi     |
    |  3 | wangwu   |
    |  1 | zhangsan |
    | 28 | zhaoliu  |
    +----+----------+
    4 rows in set
    
    mysql> show status like 'last_query_cost';
    +-----------------+------------+
    | Variable_name   | Value      |
    +-----------------+------------+
    | Last_query_cost | 876.799000 |
    +-----------------+------------+
    1 row in set
    
    mysql> select s.id,s.name from salarie s inner join (select id,name from salarie s1 group by(s1.name)) s2 using(name,id);
    +----+----------+
    | id | name     |
    +----+----------+
    |  2 | lisi     |
    |  3 | wangwu   |
    |  1 | zhangsan |
    | 28 | zhaoliu  |
    +----+----------+
    4 rows in set
    
    mysql> show status like 'last_query_cost';
    +-----------------+----------+
    | Variable_name   | Value    |
    +-----------------+----------+
    | Last_query_cost | 0.000000 |
    +-----------------+----------+
    1 row in set

     12: group by 中的 排序规则

    mysql> select * from salarie group by name;   -- mysql  会默认使用name作为排序字段
    +----------+--------+----+
    | name     | salary | id |
    +----------+--------+----+
    | lisi     |   2600 |  2 |
    | wangwu   |   3000 |  3 |
    | zhangsan |   2100 |  1 |
    | zhaoliu  |   1300 | 28 |
    +----------+--------+----+
    4 rows in set
    
    mysql> select * from salarie group by name order by null;       -- 不需要排序
    +----------+--------+----+
    | name     | salary | id |
    +----------+--------+----+
    | zhangsan |   2100 |  1 |
    | lisi     |   2600 |  2 |
    | wangwu   |   3000 |  3 |
    | zhaoliu  |   1300 | 28 |
    +----------+--------+----+
    4 rows in set
    mysql> select * from salarie group by name order by salary;   -- 指定排序字段
    +----------+--------+----+
    | name     | salary | id |
    +----------+--------+----+
    | zhaoliu  |   1300 | 28 |
    | zhangsan |   2100 |  1 |
    | lisi     |   2600 |  2 |
    | wangwu   |   3000 |  3 |
    +----------+--------+----+
    4 rows in set

     13:如果一个索引包含(或覆盖)所有需要查询的字段的值,称为‘覆盖索引’。即只需扫描索引而无须回表。只需要读取索引,而不需要读取行数据。

     14 当查询limit 10000,20时,前10000行将会被丢掉,可以使用覆盖索引进行偏移。

    mysql> select id,name from salarie order by salary limit 10,5;
    +----+--------+
    | id | name   |
    +----+--------+
    |  9 | wangwu |
    |  4 | wangwu |
    |  5 | wangwu |
    |  6 | wangwu |
    |  7 | wangwu |
    +----+--------+
    5 rows in set
    
    -- 覆盖索引 mysql
    > select id,name from salarie inner join (select id from salarie order by salary limit 10,5) s1 using(id); +----+--------+ | id | name | +----+--------+ | 9 | wangwu | | 4 | wangwu | | 5 | wangwu | | 6 | wangwu | | 7 | wangwu | +----+--------+ 5 rows in set mysql> show status like 'last_query_cost'; +-----------------+----------+ | Variable_name | Value | +-----------------+----------+ | Last_query_cost | 0.000000 | +-----------------+----------+ 1 row in set

     15:查询每次sql计算的时间

          

    mysql> set profiling=1;  -- 开启计算时间的统计
    Query OK, 0 rows affected
    
    mysql> select id,name from salarie order by salary limit 10,5;
    +----+--------+
    | id | name   |
    +----+--------+
    |  9 | wangwu |
    |  4 | wangwu |
    |  5 | wangwu |
    |  6 | wangwu |
    |  7 | wangwu |
    +----+--------+
    5 rows in set
    
    mysql> show profiles;
    +----------+------------+--------------------------------------------------------+
    | Query_ID | Duration   | Query                                                  |
    +----------+------------+--------------------------------------------------------+
    |        1 | 0.00031275 | select id,name from salarie order by salary limit 10,5 |
    |        2 |    7.65E-5 | show profiling                                         |
    +----------+------------+--------------------------------------------------------+
    2 rows in set
    
    mysql> select id,name from salarie inner join (select id from salarie order by salary limit 10,5) s1 using(id);
    
    +----+--------+
    | id | name   |
    +----+--------+
    |  9 | wangwu |
    |  4 | wangwu |
    |  5 | wangwu |
    |  6 | wangwu |
    |  7 | wangwu |
    +----+--------+
    5 rows in set
    
    mysql> show profiles;  -- 展示每次查询的时间
    +----------+------------+---------------------------------------------------------------------------------------------------------+
    | Query_ID | Duration   | Query                                                                                                   |
    +----------+------------+---------------------------------------------------------------------------------------------------------+
    |        1 | 0.00031275 | select id,name from salarie order by salary limit 10,5                                                  |
    |        2 |    7.65E-5 | show profiling                                                                                          |
    |        3 |  0.0005115 | select id,name from salarie inner join (select id from salarie order by salary limit 10,5) s1 using(id) |
    +----------+------------+---------------------------------------------------------------------------------------------------------+
    3 rows in set
    
    mysql> set profiling=0;  --  关闭每次查询的时间
    Query OK, 0 rows affected
    
    mysql> 

     16:查询缓存:当查询的数据中有now(),current_date等函数时,这些数据就不能缓存。因为每次查询都不一样。

     17:全文索引,有一个单词字典,然后在单词下面保存包含该单词的记录。

           例如;

    记录1   中华人民共和国

    记录2   中华人民

    人民[记录1,记录2]

    共和国[记录1]

    18:  可伸缩性就是在 保持性能的情况下,提高应用的负载。

    19:可伸缩性要将功能进行拆分。如果你没有做过冗余和高可用规划,那么一个节点可能就是一台服务器。如果你正在设计一个带有容错能力的冗余系统,那一个节点通常会是一下几种情况。

       a: 主-主双机拓扑结构

    b:一主多从结构

    c:一台主服务器,并有一个分布式数据块复制设备。

    d:一个机遇存储区域网络的集群。

    参考:https://blog.csdn.net/weixin_41888013/article/details/80879704

  • 相关阅读:
    快逸报表调用存储过程(SqlServer)
    一个睡五分钟等于六个钟头的方法 (转)
    Windows Live Writer For Windows Server 2003
    设计模式装饰者模式
    SqlServerCUBE
    Android 70道面试题汇总不再愁面试
    说服力:让你的PPT会说话
    亮剑Java项目开发案例导航
    初入社会必知的88个潜规则
    android UI进阶之仿iphone的tab效果2
  • 原文地址:https://www.cnblogs.com/liyafei/p/9511809.html
Copyright © 2020-2023  润新知