高性能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

原文地址:https://www.cnblogs.com/liyafei/p/9511809.html