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