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
来源:oschina
链接:https://my.oschina.net/u/4361539/blog/3857425