- 浏览: 243455 次
最新评论
数据库调优分享------参考一本mysql资料书
日常的困扰
**反映查询某个数据越来越慢,怎么办?
数据库监控页面显示某个操作频繁执行,每次执行都非常耗时,怎么办?
1.Sql优化
2.合理使用索引
一、sql优化—常用方法
1)not in 子查询优化
2)模糊匹配 like ‘%abc%’
3)limit分页优化
4)count(*)统计数据如何加快速度
5)or条件如何优化
6)用where子句代替having子句
1、not in 子查询优化
SELECT count(*) FROM t_cps t1 where t1.flag>=2 and sample_md5 not in (select sample_hash from t_sfa_sample t2 where t2.sample_hash=t1.sample_md5);
-1052661行记录
33.530s
SELECT count(*) FROM t_cps t1 where t1.flag>=2 and not exists(select sample_hash from t_sfa_sample t2 where t2.sample_hash=t1.sample_md5);
-1052661行记录
18.617s
SELECT count(*) FROM t_cps t1 left join t_sfa_sample t2 on t1.sample_md5=t2.sample_hash where t1.flag>=2 and t2.sample_hash is null;
-1052661行记录
14.544s
生产环境中,尽量避免使用子查询,可用表连接join代替。可避免mysql在内存中创建临时表
in和exists
SELECT count(*) FROM t_cps t1 where t1.flag>=2 and sample_md5 in (select sample_hash from t_sfa_sample t2 where t2.sample_hash=t1.sample_md5);
1227992行记录
30.762s
SELECT count(*) FROM t_cps t1 where t1.flag>=2 and exists (select sample_hash from t_sfa_sample t2 where t2.sample_hash=t1.sample_md5);
1227992行记录
15.581s
in和exists执行时:
in是先执行子查询中的查询,然后再执行主查询。
exists是先执行主查询,即外层表的查询,然后再执行子查询
exists 和 in 在执行时效率单从执行时间来说差不多,exists要稍微优于in。在使用时一般应该是用exists而不用in
而在not in 和 not exists比较时,not exists的效率要比not in的效率要高。
但也有少数时候并非如此。
建议是尽量多使用exists和not exists,少用in 和not in
2、模糊匹配 like ‘%abc%’
mysql> explain select * from update_log_test where msg like 'e%';
+----+-------------+-----------------+-------+---------------+---------+---------+------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------------+-------+---------------+---------+---------+------+------+-----------------------+
| 1 | SIMPLE | update_log_test | range | idx_msg | idx_msg | 768 | NULL | 1 | Using index condition |
+----+-------------+-----------------+-------+---------------+---------+---------+------+------+-----------------------+
1 row in set (0.00 sec)
mysql> explain select * from update_log_test where msg like '%e%';
+----+-------------+-----------------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | update_log_test | ALL | NULL | NULL | NULL | NULL | 4 | Using where |
+----+-------------+-----------------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
like ‘abc%’可以用到索引,但like‘%abc%’却不行。
SELECT * FROM books WHERE name like "MySQL%" ;
但是如果换用下面的查询,返回的结果一样,但速度就要快上很多:
SELECT * FROM books WHERE name>="MySQL"and name<"MySQM" ;
补充:explain列的解释
table 显示这一行的数据是关于哪张表的
type 这是重要的列,显示连接使用了何种类型。从最好到最差的连接类型为const、eq_reg、ref、range、index和ALL
possible_keys 显示可能应用在这张表中的索引。如果为空,没有可能的索引。
key 实际使用的索引。如果为NULL,则没有使用索引。很少的情况下,MYSQL会选择优化不足的索引。这种情况下,可以在SELECT语句中使用USE INDEX(indexname)来强制使用一个索引或者用IGNORE INDEX(indexname)来强制MYSQL忽略索引
key_len 使用的索引的长度。在不损失精确性的情况下,长度越短越好
ref 显示索引的哪一列被使用了,显示了哪些字段或者常量被用来和 key配合从表中查询记录出来。
rows MYSQL认为必须检查的用来返回请求数据的行数
Extra 关于MYSQL如何解析查询的额外信息。这里可以看到的坏的例子是Using temporary和Using filesort,意思MYSQL根本不能使用索引,检索会很慢
type不同连接类型的解释(按照效率高低的顺序排序)
const 索引可以是主键或惟一索引,因为只有一行,这个值实际就是常数,因为MYSQL先读这个值然后把它当做常数来对待
mysql> explain select * from update_log_20141111 where id=2;
+----+-------------+---------------------+-------+---------------+---------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------------------+-------+---------------+---------+---------+-------+------+-------+
| 1 | SIMPLE | update_log_20141111 | const | PRIMARY | PRIMARY | 4 | const | 1 | NULL |
+----+-------------+---------------------+-------+---------------+---------+---------+-------+------+-------+
eq_ref 从前面的表中,对每一个记录的联合都从表中读取一个记录,它在查询使用了索引为主键或惟一键的全部时使用
mysql> explain select * from t1,t2 where t1.id=t2.id;
+----+-------------+-------+--------+---------------+---------+---------+------------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+------------+------+-------+
| 1 | SIMPLE | t2 | ALL | PRIMARY | NULL | NULL | NULL | 9 | NULL |
| 1 | SIMPLE | t1 | eq_ref | PRIMARY | PRIMARY | 4 | test.t2.id | 1 | NULL |
+----+-------------+-------+--------+---------------+---------+---------+------------+------+-------+
2 rows in set (0.00 sec)
ref 只有在查询使用了不是惟一或主键的键或者是这些类型的部分(比如,利用最左边前缀)时发生。对于之前的表的每一个行联合,全部记录都将从表中读出。这个类型严重依赖于根据索引匹配的记录多少—越少越好
mysql> explain select * from update_log_20141110 t1,update_log_test t2 where t1.action=t2.action;
+----+-------------+-------+------+---------------+----------+---------+----------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+----------+---------+----------------+------+-------------+
| 1 | SIMPLE | t1 | ALL | i_action | NULL | NULL | NULL | 2 | Using where |
| 1 | SIMPLE | t2 | ref | i_action | i_action | 2 | test.t1.action | 1 | NULL |
+----+-------------+-------+------+---------------+----------+---------+----------------+------+-------------+
2 rows in set (0.00 sec)
range 返回一个范围中的行,比如使用>或<查找东西时
mysql> explain select * from t1 where id>=9900 order by id limit 10;
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| 1 | SIMPLE | t1 | range | PRIMARY | PRIMARY | 4 | NULL | 101 | Using where |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
1 row in set (0.00 sec)
index 对前面的表中的每一个记录联合进行完全扫描(比ALL更好,因为索引一般小于表数据)
ALL 对每一个记录联合进行完全扫描,这一般比较糟糕,应该尽量避免
Extra 列返回的描述的意义
Distinct 一旦MYSQL找到了与行相联合匹配的行,就不再搜索了
Not exists MYSQL优化了LEFT JOIN,一旦它找到了匹配LEFT JOIN标准的行,就不再搜索
Record(index map:#)没有找到理想的索引,因此对于从前面表中来的每一个行组合,MYSQL检查使用哪个索引,并用它来从表中返回行。这是使用索引的最慢的连接之一
Using filesort 看到这个的时候,查询就需要优化了。MYSQL需要进行额外的步骤来发现如何对返回的行排序。它根据连接类型以及存储排序键值和匹配条件的全部行的行指针来排序全部行
Using index 列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,这发生在对表的全部的请求列都是同一个索引的部分的时候
Using temporary 看到这个的时候,查询需要优化了。这里,MYSQL需要创建一个临时表来存储结果,这通常发生在对不同的列集进行ORDER BY上,而不是GROUP BY上
Using where 使用了WHERE从句来限制哪些行将与下一张表匹配或者是返回给用户。如果不想返回表中的全部行,并且连接类型ALL或index,这就会发生,或者是查询有问题
3、limit分页优化
Select * from t1 order by id limit 9900,10;
上面的语句,虽然用到了id索引,但是从第一行开始起定位至9900行,然后再扫描后10行,相当于进行了一次全扫描,显然效率不高。
Select * from t1 where id>=9900 order by id limit 10;
利用id索引直接定位到9900行,然后在扫描出后10行,相当于一个range范围扫描
mysql> explain select * from t1 order by id limit 9900,10;
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------+
| 1 | SIMPLE | t1 | index | NULL | PRIMARY | 4 | NULL | 9910 | NULL |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------+
1 row in set (0.00 sec)
mysql> explain select * from t1 where id>=9900 order by id limit 10;
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| 1 | SIMPLE | t1 | range | PRIMARY | PRIMARY | 4 | NULL | 101 | Using where |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
1 row in set (0.00 sec)
4、count(*)统计数据如何加快速度
select count(*) from update_log;
select count(*) from update_log where sid>=0; 利用辅助索引
select count(distinct k) from t;
select count(*) from (select distinct k from t) tmp; 利用索引来做排重操作。
注意:innodb count(*)必须全表扫,而不像myisam那样有一个计数器,直接从中取出数据。Innodb必须要全表扫一次才能得到count,而且会锁表。
5、or条件如何优化
select * from user where name='d' or age=31;
name和age都建立了索引,但explain发现这个or条件用不到索引。
改成union all结果集合并
select * from user where name='d' union all select * from user where age=31;
6、用where子句代替having子句
select * from user group by id having id>40 limit 3;
select * from user where id>40 group by id limit 3;
having只会在检索出所有记录之后才对结果集进行过滤。这个处理需要排序、总计等操作。
如果能通过where子句限制记录的数目,那就能减少这方面的开销。
SQL优化的一般步骤
1、通过 show status 命令了解各种SQL的执行频率
show status like 'uptime' 当前MySQL运行时间
show status like 'com_select' 当前MySQL执行了多少次查询
show status like 'com_insert' 当前MySQL执行了多少次添加
show status like 'com_update' 当前MySQL执行了多少次更新
show status like 'com_delete' 当前MySQL执行了多少次删除
show status 语法:
show [session|global] status like '';
如果不写 [session|global] 表示默认是 session 指取出当前窗口的执行情况
如果想看所有(mysql启动到现在)的情况 加上 global
show global status like 'com_insert';
2、 定位执行效率较低的SQL语句 (重点select)
3、通过 explain 分析低效率的SQL语句的执行情况
4、确定问题并采取相应的优化措施
二、合理使用索引
使用索引,why?
单列索引和联合索引
字段使用函数,将不能走索引
当取出的数据量超过表中数据的20%,索引是否有效?
order by 和group by优化
全文索引
1、适当的索引对应用的性能来说至关重要。
2、索引只对select有加速作用,但对写入(insert,update、delete)操作会带来额外的开销,如果带有一个或多个索引,那么数据更新的时候,mysql也要更新各个索引。
3、并不是所有经常查询的列都适合创建索引,区分度不高的,通常走全表扫浏览会更快。例如性别,只有男女两种,就不适合。
4、一条sql只能用一个索引,如果有多个,优化器会选择最优的。
1、单列索引和联合索引
mysql> create index i_s_time on update_log(server,time);
联合索引要遵循最左侧原则
mysql> explain select * from update_log where server='115.29.138.24' and time='13:00:00';
+----+-------------+------------+------+-----------------+----------+---------+-------------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+-----------------+----------+---------+-------------+------+-----------------------+
| 1 | SIMPLE | update_log | ref | i_time,i_s_time | i_s_time | 50 | const,const | 7 | Using index condition |
+----+-------------+------------+------+-----------------+----------+---------+-------------+------+-----------------------+
1 row in set (0.00 sec)
mysql> explain select * from update_log where server='115.29.138.24';
+----+-------------+------------+------+---------------+----------+---------+-------+---------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+----------+---------+-------+---------+-----------------------+
| 1 | SIMPLE | update_log | ref | i_s_time | i_s_time | 46 | const | 2653264 | Using index condition |
+----+-------------+------------+------+---------------+----------+---------+-------+---------+-----------------------+
1 row in set (0.00 sec)
mysql> explain select * from update_log where server='115.29.138.24' and client='14.197.74.21' and time='13:00:00';
+----+-------------+------------+------+-----------------+----------+---------+-------------+------+------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+-----------------+----------+---------+-------------+------+------------------------------------+
| 1 | SIMPLE | update_log | ref | i_time,i_s_time | i_s_time | 50 | const,const | 7 | Using index condition; Using where |
+----+-------------+------------+------+-----------------+----------+---------+-------------+------+------------------------------------+
1 row in set (0.00 sec)
mysql> explain select * from update_log where time='13:00:00';
+----+-------------+------------+------+---------------+------+---------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+------+---------+------+----------+-------------+
| 1 | SIMPLE | update_log | ALL | NULL | NULL | NULL | NULL | 21615394 | Using where |
+----+-------------+------------+------+---------------+------+---------+------+----------+-------------+
1 row in set (0.00 sec)
2、字段使用函数,将不能走索引 --mysql目前还不支持函数索引
mysql> explain select * from update_log where year(date)<2014;
+----+-------------+------------+------+---------------+------+---------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+------+---------+------+----------+-------------+
| 1 | SIMPLE | update_log | ALL | NULL | NULL | NULL | NULL | 21615394 | Using where |
+----+-------------+------------+------+---------------+------+---------+------+----------+-------------+
1 row in set (0.00 sec)
在where后面的查询条件字段使用了date()函数,是不会用到索引的。
mysql> explain select * from update_log where date<'2014-01-01';
+----+-------------+------------+-------+---------------+------+---------+------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+---------------+------+---------+------+------+-----------------------+
| 1 | SIMPLE | update_log | range | date | date | 4 | NULL | 1 | Using index condition |
+----+-------------+------------+-------+---------------+------+---------+------+------+-----------------------+
1 row in set (0.00 sec)
同样的情形也会发生在对数值型字段进行计算的时候:
SELECT * FROM t1 WHERE Amount/7<24;
SELECT * FROM t1 WHERE Amount<24*7;
3、无引号导致全表扫描,无法使用索引
mysql> explain select * from update_log_test where msg=123;
+----+-------------+-----------------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | update_log_test | ALL | i_msg | NULL | NULL | NULL | 4 | Using where |
+----+-------------+-----------------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
mysql> explain select * from update_log_test where msg='yoyo';
+----+-------------+-----------------+------+---------------+-------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------------+------+---------------+-------+---------+-------+------+-----------------------+
| 1 | SIMPLE | update_log_test | ref | i_msg | i_msg | 768 | const | 1 | Using index condition |
+----+-------------+-----------------+------+---------------+-------+---------+-------+------+-----------------------+
由于msg是varchar类型,因此查询的时候,必须加‘’
数字当字符类型使用时,也一定要加上。
4、当取出的数据量超过表中数据的20%,优化器认为全表扫更快,不会走索引
mysql> explain select * from update_log where time<'14:00:00';
+----+-------------+------------+------+---------------+------+---------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+------+---------+------+----------+-------------+
| 1 | SIMPLE | update_log | ALL | i_time | NULL | NULL | NULL | 21615394 | Using where |
+----+-------------+------------+------+---------------+------+---------+------+----------+-------------+
1 row in set (0.00 sec)
mysql> explain select * from update_log where time<'14:00:00' and time>'13:00:00';
+----+-------------+------------+-------+---------------+--------+---------+------+---------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+---------------+--------+---------+------+---------+-----------------------+
| 1 | SIMPLE | update_log | range | i_time | i_time | 4 | NULL | 3013332 | Using index condition |
+----+-------------+------------+-------+---------------+--------+---------+------+---------+-----------------------+
1 row in set (0.00 sec)
5、order by 和group by优化
mysql> explain select * from update_log where server='115.29.138.24' order by time;
+----+-------------+------------+------+---------------+------+---------+------+----------+-----------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+------+---------+------+----------+-----------------------------+
| 1 | SIMPLE | update_log | ALL | NULL | NULL | NULL | NULL | 21615394 | Using where; Using filesort |
+----+-------------+------------+------+---------------+------+---------+------+----------+-----------------------------+
1 row in set (0.00 sec)
创建联合索引
mysql> create index i_s_time on update_log(server,time);
Query OK, 0 rows affected (3 min 18.94 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> explain select * from update_log where server='115.29.138.24' order by time;
+----+-------------+------------+------+---------------+----------+---------+-------+---------+------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+----------+---------+-------+---------+------------------------------------+
| 1 | SIMPLE | update_log | ref | i_s_time | i_s_time | 46 | const | 2653264 | Using index condition; Using where |
+----+-------------+------------+------+---------------+----------+---------+-------+---------+------------------------------------+
1 row in set (0.01 sec)
如果order by 后面有多个字段排序,它们的顺序要一致,如果一个是降序,一个是升序,也会出现using filesort排序。
6、全文索引
全文索引:主要是针对文件,文本的索引,比如文章(5.6开始innodb也支持)
字段类型:char、varchar、text
全文搜索通过 MATCH() 函数完成.
mysql> create table articles(
-> id int unsigned auto_increment not null primary key,
-> title varchar(200),
-> body text,
-> fulltext(title,body));
Query OK, 0 rows affected (0.05 sec)
mysql> INSERT INTO articles VALUES
-> (NULL,'MySQL Tutorial', 'DBMS stands for DataBase ...'),
-> (NULL,'How To Use MySQL Efficiently', 'After you went through a ...'),
-> (NULL,'Optimising MySQL','In this tutorial we will show ...'),
-> (NULL,'1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'),
-> (NULL,'MySQL vs. YourSQL', 'In the following database comparison ...'),
-> (NULL,'MySQL Security', 'When configured properly, MySQL ...');
Query OK, 6 rows affected (0.01 sec)
Records: 6 Duplicates: 0 Warnings: 0
mysql> explain select * from articles where match(title,body) against('database');
+----+-------------+----------+----------+---------------+-------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+----------+---------------+-------+---------+------+------+-------------+
| 1 | SIMPLE | articles | fulltext | title | title | 0 | NULL | 1 | Using where |
+----+-------------+----------+----------+---------------+-------+---------+------+------+-------------+
1 row in set (0.00 sec)
但如果某个单词单词出现在至少全文的50%的行中,它会被列入停止字。对于大型数据集,使用这个操作最合适不过了----一个自然语言问询不会从一个1GB 的表每隔一行返回一次。对于小型数据集,它的用处可能比较小。不是大型的数据量,就不要用他,影响插入速度
7、mysql 5.6支持explain update/delete
mysql> explain update update_log_test set msg='gugu' where id=4;
+----+-------------+-----------------+-------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------------+-------+---------------+---------+---------+-------+------+-------------+
| 1 | SIMPLE | update_log_test | range | PRIMARY | PRIMARY | 4 | const | 1 | Using where |
+----+-------------+-----------------+-------+---------------+---------+---------+-------+------+-------------+
1 row in set (0.01 sec)
mysql> explain delete from update_log_test where id=4;
+----+-------------+-----------------+-------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------------+-------+---------------+---------+---------+-------+------+-------------+
| 1 | SIMPLE | update_log_test | range | PRIMARY | PRIMARY | 4 | const | 1 | Using where |
+----+-------------+-----------------+-------+---------------+---------+---------+-------+------+-------------+
1 row in set (0.00 sec)
8、mysql5.6优化了合并索引
mysql> explain select * from update_log where date='2014-11-12' or time='14:00:00';
+----+-------------+------------+-------------+---------------+-------------+---------+------+----------+---------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------------+---------------+-------------+---------+------+----------+---------------------------------------+
| 1 | SIMPLE | update_log | index_merge | date,i_time | date,i_time | 4,4 | NULL | 10808103 | Using union(date,i_time); Using where |
+----+-------------+------------+-------------+---------------+-------------+---------+------+----------+---------------------------------------+
1 row in set (0.01 sec)
mysql> explain select * from update_log where date='2014-11-12' union select * from update_log where time='14:00:00';
+----+--------------+------------+------+---------------+--------+---------+-------+----------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------+------------+------+---------------+--------+---------+-------+----------+-----------------------+
| 1 | PRIMARY | update_log | ref | date | date | 4 | const | 10807697 | NULL |
| 2 | UNION | update_log | ref | i_time | i_time | 4 | const | 406 | Using index condition |
| NULL | UNION RESULT | <union1,2> | ALL | NULL | NULL | NULL | NULL | NULL | Using temporary |
+----+--------------+------------+------+---------------+--------+---------+-------+----------+-----------------------+
3 rows in set (0.00 sec)
实际测试2条sql,or的执行时间是union执行时间的两倍。
1、union all 不一定就比 or及in 快,要结合实际情况分析到底使用哪种情况。
2、对于索引列来最好使用union all,因复杂的查询【包含运算等】将使or、in放弃索引而全表扫描,除非你能确定or、in会使用索引。
3、对于只有非索引字段来说你就老老实实的用or 或者in,因为 非索引字段本来要全表扫描而union all 只成倍增加表扫描的次数。
Union:对两个结果集进行并集操作,不包括重复行,同时进行默认规则的排序;Union All:对两个结果集进行并集操作,包括重复行,不进行排序;
union因为要进行重复值扫描,所以效率低。
that's all
欢迎与我交流 tina QQ:906179271
日常的困扰
**反映查询某个数据越来越慢,怎么办?
数据库监控页面显示某个操作频繁执行,每次执行都非常耗时,怎么办?
1.Sql优化
2.合理使用索引
一、sql优化—常用方法
1)not in 子查询优化
2)模糊匹配 like ‘%abc%’
3)limit分页优化
4)count(*)统计数据如何加快速度
5)or条件如何优化
6)用where子句代替having子句
1、not in 子查询优化
SELECT count(*) FROM t_cps t1 where t1.flag>=2 and sample_md5 not in (select sample_hash from t_sfa_sample t2 where t2.sample_hash=t1.sample_md5);
-1052661行记录
33.530s
SELECT count(*) FROM t_cps t1 where t1.flag>=2 and not exists(select sample_hash from t_sfa_sample t2 where t2.sample_hash=t1.sample_md5);
-1052661行记录
18.617s
SELECT count(*) FROM t_cps t1 left join t_sfa_sample t2 on t1.sample_md5=t2.sample_hash where t1.flag>=2 and t2.sample_hash is null;
-1052661行记录
14.544s
生产环境中,尽量避免使用子查询,可用表连接join代替。可避免mysql在内存中创建临时表
in和exists
SELECT count(*) FROM t_cps t1 where t1.flag>=2 and sample_md5 in (select sample_hash from t_sfa_sample t2 where t2.sample_hash=t1.sample_md5);
1227992行记录
30.762s
SELECT count(*) FROM t_cps t1 where t1.flag>=2 and exists (select sample_hash from t_sfa_sample t2 where t2.sample_hash=t1.sample_md5);
1227992行记录
15.581s
in和exists执行时:
in是先执行子查询中的查询,然后再执行主查询。
exists是先执行主查询,即外层表的查询,然后再执行子查询
exists 和 in 在执行时效率单从执行时间来说差不多,exists要稍微优于in。在使用时一般应该是用exists而不用in
而在not in 和 not exists比较时,not exists的效率要比not in的效率要高。
但也有少数时候并非如此。
建议是尽量多使用exists和not exists,少用in 和not in
2、模糊匹配 like ‘%abc%’
mysql> explain select * from update_log_test where msg like 'e%';
+----+-------------+-----------------+-------+---------------+---------+---------+------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------------+-------+---------------+---------+---------+------+------+-----------------------+
| 1 | SIMPLE | update_log_test | range | idx_msg | idx_msg | 768 | NULL | 1 | Using index condition |
+----+-------------+-----------------+-------+---------------+---------+---------+------+------+-----------------------+
1 row in set (0.00 sec)
mysql> explain select * from update_log_test where msg like '%e%';
+----+-------------+-----------------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | update_log_test | ALL | NULL | NULL | NULL | NULL | 4 | Using where |
+----+-------------+-----------------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
like ‘abc%’可以用到索引,但like‘%abc%’却不行。
SELECT * FROM books WHERE name like "MySQL%" ;
但是如果换用下面的查询,返回的结果一样,但速度就要快上很多:
SELECT * FROM books WHERE name>="MySQL"and name<"MySQM" ;
补充:explain列的解释
table 显示这一行的数据是关于哪张表的
type 这是重要的列,显示连接使用了何种类型。从最好到最差的连接类型为const、eq_reg、ref、range、index和ALL
possible_keys 显示可能应用在这张表中的索引。如果为空,没有可能的索引。
key 实际使用的索引。如果为NULL,则没有使用索引。很少的情况下,MYSQL会选择优化不足的索引。这种情况下,可以在SELECT语句中使用USE INDEX(indexname)来强制使用一个索引或者用IGNORE INDEX(indexname)来强制MYSQL忽略索引
key_len 使用的索引的长度。在不损失精确性的情况下,长度越短越好
ref 显示索引的哪一列被使用了,显示了哪些字段或者常量被用来和 key配合从表中查询记录出来。
rows MYSQL认为必须检查的用来返回请求数据的行数
Extra 关于MYSQL如何解析查询的额外信息。这里可以看到的坏的例子是Using temporary和Using filesort,意思MYSQL根本不能使用索引,检索会很慢
type不同连接类型的解释(按照效率高低的顺序排序)
const 索引可以是主键或惟一索引,因为只有一行,这个值实际就是常数,因为MYSQL先读这个值然后把它当做常数来对待
mysql> explain select * from update_log_20141111 where id=2;
+----+-------------+---------------------+-------+---------------+---------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------------------+-------+---------------+---------+---------+-------+------+-------+
| 1 | SIMPLE | update_log_20141111 | const | PRIMARY | PRIMARY | 4 | const | 1 | NULL |
+----+-------------+---------------------+-------+---------------+---------+---------+-------+------+-------+
eq_ref 从前面的表中,对每一个记录的联合都从表中读取一个记录,它在查询使用了索引为主键或惟一键的全部时使用
mysql> explain select * from t1,t2 where t1.id=t2.id;
+----+-------------+-------+--------+---------------+---------+---------+------------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+------------+------+-------+
| 1 | SIMPLE | t2 | ALL | PRIMARY | NULL | NULL | NULL | 9 | NULL |
| 1 | SIMPLE | t1 | eq_ref | PRIMARY | PRIMARY | 4 | test.t2.id | 1 | NULL |
+----+-------------+-------+--------+---------------+---------+---------+------------+------+-------+
2 rows in set (0.00 sec)
ref 只有在查询使用了不是惟一或主键的键或者是这些类型的部分(比如,利用最左边前缀)时发生。对于之前的表的每一个行联合,全部记录都将从表中读出。这个类型严重依赖于根据索引匹配的记录多少—越少越好
mysql> explain select * from update_log_20141110 t1,update_log_test t2 where t1.action=t2.action;
+----+-------------+-------+------+---------------+----------+---------+----------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+----------+---------+----------------+------+-------------+
| 1 | SIMPLE | t1 | ALL | i_action | NULL | NULL | NULL | 2 | Using where |
| 1 | SIMPLE | t2 | ref | i_action | i_action | 2 | test.t1.action | 1 | NULL |
+----+-------------+-------+------+---------------+----------+---------+----------------+------+-------------+
2 rows in set (0.00 sec)
range 返回一个范围中的行,比如使用>或<查找东西时
mysql> explain select * from t1 where id>=9900 order by id limit 10;
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| 1 | SIMPLE | t1 | range | PRIMARY | PRIMARY | 4 | NULL | 101 | Using where |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
1 row in set (0.00 sec)
index 对前面的表中的每一个记录联合进行完全扫描(比ALL更好,因为索引一般小于表数据)
ALL 对每一个记录联合进行完全扫描,这一般比较糟糕,应该尽量避免
Extra 列返回的描述的意义
Distinct 一旦MYSQL找到了与行相联合匹配的行,就不再搜索了
Not exists MYSQL优化了LEFT JOIN,一旦它找到了匹配LEFT JOIN标准的行,就不再搜索
Record(index map:#)没有找到理想的索引,因此对于从前面表中来的每一个行组合,MYSQL检查使用哪个索引,并用它来从表中返回行。这是使用索引的最慢的连接之一
Using filesort 看到这个的时候,查询就需要优化了。MYSQL需要进行额外的步骤来发现如何对返回的行排序。它根据连接类型以及存储排序键值和匹配条件的全部行的行指针来排序全部行
Using index 列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,这发生在对表的全部的请求列都是同一个索引的部分的时候
Using temporary 看到这个的时候,查询需要优化了。这里,MYSQL需要创建一个临时表来存储结果,这通常发生在对不同的列集进行ORDER BY上,而不是GROUP BY上
Using where 使用了WHERE从句来限制哪些行将与下一张表匹配或者是返回给用户。如果不想返回表中的全部行,并且连接类型ALL或index,这就会发生,或者是查询有问题
3、limit分页优化
Select * from t1 order by id limit 9900,10;
上面的语句,虽然用到了id索引,但是从第一行开始起定位至9900行,然后再扫描后10行,相当于进行了一次全扫描,显然效率不高。
Select * from t1 where id>=9900 order by id limit 10;
利用id索引直接定位到9900行,然后在扫描出后10行,相当于一个range范围扫描
mysql> explain select * from t1 order by id limit 9900,10;
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------+
| 1 | SIMPLE | t1 | index | NULL | PRIMARY | 4 | NULL | 9910 | NULL |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------+
1 row in set (0.00 sec)
mysql> explain select * from t1 where id>=9900 order by id limit 10;
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| 1 | SIMPLE | t1 | range | PRIMARY | PRIMARY | 4 | NULL | 101 | Using where |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
1 row in set (0.00 sec)
4、count(*)统计数据如何加快速度
select count(*) from update_log;
select count(*) from update_log where sid>=0; 利用辅助索引
select count(distinct k) from t;
select count(*) from (select distinct k from t) tmp; 利用索引来做排重操作。
注意:innodb count(*)必须全表扫,而不像myisam那样有一个计数器,直接从中取出数据。Innodb必须要全表扫一次才能得到count,而且会锁表。
5、or条件如何优化
select * from user where name='d' or age=31;
name和age都建立了索引,但explain发现这个or条件用不到索引。
改成union all结果集合并
select * from user where name='d' union all select * from user where age=31;
6、用where子句代替having子句
select * from user group by id having id>40 limit 3;
select * from user where id>40 group by id limit 3;
having只会在检索出所有记录之后才对结果集进行过滤。这个处理需要排序、总计等操作。
如果能通过where子句限制记录的数目,那就能减少这方面的开销。
SQL优化的一般步骤
1、通过 show status 命令了解各种SQL的执行频率
show status like 'uptime' 当前MySQL运行时间
show status like 'com_select' 当前MySQL执行了多少次查询
show status like 'com_insert' 当前MySQL执行了多少次添加
show status like 'com_update' 当前MySQL执行了多少次更新
show status like 'com_delete' 当前MySQL执行了多少次删除
show status 语法:
show [session|global] status like '';
如果不写 [session|global] 表示默认是 session 指取出当前窗口的执行情况
如果想看所有(mysql启动到现在)的情况 加上 global
show global status like 'com_insert';
2、 定位执行效率较低的SQL语句 (重点select)
3、通过 explain 分析低效率的SQL语句的执行情况
4、确定问题并采取相应的优化措施
二、合理使用索引
使用索引,why?
单列索引和联合索引
字段使用函数,将不能走索引
当取出的数据量超过表中数据的20%,索引是否有效?
order by 和group by优化
全文索引
1、适当的索引对应用的性能来说至关重要。
2、索引只对select有加速作用,但对写入(insert,update、delete)操作会带来额外的开销,如果带有一个或多个索引,那么数据更新的时候,mysql也要更新各个索引。
3、并不是所有经常查询的列都适合创建索引,区分度不高的,通常走全表扫浏览会更快。例如性别,只有男女两种,就不适合。
4、一条sql只能用一个索引,如果有多个,优化器会选择最优的。
1、单列索引和联合索引
mysql> create index i_s_time on update_log(server,time);
联合索引要遵循最左侧原则
mysql> explain select * from update_log where server='115.29.138.24' and time='13:00:00';
+----+-------------+------------+------+-----------------+----------+---------+-------------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+-----------------+----------+---------+-------------+------+-----------------------+
| 1 | SIMPLE | update_log | ref | i_time,i_s_time | i_s_time | 50 | const,const | 7 | Using index condition |
+----+-------------+------------+------+-----------------+----------+---------+-------------+------+-----------------------+
1 row in set (0.00 sec)
mysql> explain select * from update_log where server='115.29.138.24';
+----+-------------+------------+------+---------------+----------+---------+-------+---------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+----------+---------+-------+---------+-----------------------+
| 1 | SIMPLE | update_log | ref | i_s_time | i_s_time | 46 | const | 2653264 | Using index condition |
+----+-------------+------------+------+---------------+----------+---------+-------+---------+-----------------------+
1 row in set (0.00 sec)
mysql> explain select * from update_log where server='115.29.138.24' and client='14.197.74.21' and time='13:00:00';
+----+-------------+------------+------+-----------------+----------+---------+-------------+------+------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+-----------------+----------+---------+-------------+------+------------------------------------+
| 1 | SIMPLE | update_log | ref | i_time,i_s_time | i_s_time | 50 | const,const | 7 | Using index condition; Using where |
+----+-------------+------------+------+-----------------+----------+---------+-------------+------+------------------------------------+
1 row in set (0.00 sec)
mysql> explain select * from update_log where time='13:00:00';
+----+-------------+------------+------+---------------+------+---------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+------+---------+------+----------+-------------+
| 1 | SIMPLE | update_log | ALL | NULL | NULL | NULL | NULL | 21615394 | Using where |
+----+-------------+------------+------+---------------+------+---------+------+----------+-------------+
1 row in set (0.00 sec)
2、字段使用函数,将不能走索引 --mysql目前还不支持函数索引
mysql> explain select * from update_log where year(date)<2014;
+----+-------------+------------+------+---------------+------+---------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+------+---------+------+----------+-------------+
| 1 | SIMPLE | update_log | ALL | NULL | NULL | NULL | NULL | 21615394 | Using where |
+----+-------------+------------+------+---------------+------+---------+------+----------+-------------+
1 row in set (0.00 sec)
在where后面的查询条件字段使用了date()函数,是不会用到索引的。
mysql> explain select * from update_log where date<'2014-01-01';
+----+-------------+------------+-------+---------------+------+---------+------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+---------------+------+---------+------+------+-----------------------+
| 1 | SIMPLE | update_log | range | date | date | 4 | NULL | 1 | Using index condition |
+----+-------------+------------+-------+---------------+------+---------+------+------+-----------------------+
1 row in set (0.00 sec)
同样的情形也会发生在对数值型字段进行计算的时候:
SELECT * FROM t1 WHERE Amount/7<24;
SELECT * FROM t1 WHERE Amount<24*7;
3、无引号导致全表扫描,无法使用索引
mysql> explain select * from update_log_test where msg=123;
+----+-------------+-----------------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | update_log_test | ALL | i_msg | NULL | NULL | NULL | 4 | Using where |
+----+-------------+-----------------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
mysql> explain select * from update_log_test where msg='yoyo';
+----+-------------+-----------------+------+---------------+-------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------------+------+---------------+-------+---------+-------+------+-----------------------+
| 1 | SIMPLE | update_log_test | ref | i_msg | i_msg | 768 | const | 1 | Using index condition |
+----+-------------+-----------------+------+---------------+-------+---------+-------+------+-----------------------+
由于msg是varchar类型,因此查询的时候,必须加‘’
数字当字符类型使用时,也一定要加上。
4、当取出的数据量超过表中数据的20%,优化器认为全表扫更快,不会走索引
mysql> explain select * from update_log where time<'14:00:00';
+----+-------------+------------+------+---------------+------+---------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+------+---------+------+----------+-------------+
| 1 | SIMPLE | update_log | ALL | i_time | NULL | NULL | NULL | 21615394 | Using where |
+----+-------------+------------+------+---------------+------+---------+------+----------+-------------+
1 row in set (0.00 sec)
mysql> explain select * from update_log where time<'14:00:00' and time>'13:00:00';
+----+-------------+------------+-------+---------------+--------+---------+------+---------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+---------------+--------+---------+------+---------+-----------------------+
| 1 | SIMPLE | update_log | range | i_time | i_time | 4 | NULL | 3013332 | Using index condition |
+----+-------------+------------+-------+---------------+--------+---------+------+---------+-----------------------+
1 row in set (0.00 sec)
5、order by 和group by优化
mysql> explain select * from update_log where server='115.29.138.24' order by time;
+----+-------------+------------+------+---------------+------+---------+------+----------+-----------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+------+---------+------+----------+-----------------------------+
| 1 | SIMPLE | update_log | ALL | NULL | NULL | NULL | NULL | 21615394 | Using where; Using filesort |
+----+-------------+------------+------+---------------+------+---------+------+----------+-----------------------------+
1 row in set (0.00 sec)
创建联合索引
mysql> create index i_s_time on update_log(server,time);
Query OK, 0 rows affected (3 min 18.94 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> explain select * from update_log where server='115.29.138.24' order by time;
+----+-------------+------------+------+---------------+----------+---------+-------+---------+------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+----------+---------+-------+---------+------------------------------------+
| 1 | SIMPLE | update_log | ref | i_s_time | i_s_time | 46 | const | 2653264 | Using index condition; Using where |
+----+-------------+------------+------+---------------+----------+---------+-------+---------+------------------------------------+
1 row in set (0.01 sec)
如果order by 后面有多个字段排序,它们的顺序要一致,如果一个是降序,一个是升序,也会出现using filesort排序。
6、全文索引
全文索引:主要是针对文件,文本的索引,比如文章(5.6开始innodb也支持)
字段类型:char、varchar、text
全文搜索通过 MATCH() 函数完成.
mysql> create table articles(
-> id int unsigned auto_increment not null primary key,
-> title varchar(200),
-> body text,
-> fulltext(title,body));
Query OK, 0 rows affected (0.05 sec)
mysql> INSERT INTO articles VALUES
-> (NULL,'MySQL Tutorial', 'DBMS stands for DataBase ...'),
-> (NULL,'How To Use MySQL Efficiently', 'After you went through a ...'),
-> (NULL,'Optimising MySQL','In this tutorial we will show ...'),
-> (NULL,'1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'),
-> (NULL,'MySQL vs. YourSQL', 'In the following database comparison ...'),
-> (NULL,'MySQL Security', 'When configured properly, MySQL ...');
Query OK, 6 rows affected (0.01 sec)
Records: 6 Duplicates: 0 Warnings: 0
mysql> explain select * from articles where match(title,body) against('database');
+----+-------------+----------+----------+---------------+-------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+----------+---------------+-------+---------+------+------+-------------+
| 1 | SIMPLE | articles | fulltext | title | title | 0 | NULL | 1 | Using where |
+----+-------------+----------+----------+---------------+-------+---------+------+------+-------------+
1 row in set (0.00 sec)
但如果某个单词单词出现在至少全文的50%的行中,它会被列入停止字。对于大型数据集,使用这个操作最合适不过了----一个自然语言问询不会从一个1GB 的表每隔一行返回一次。对于小型数据集,它的用处可能比较小。不是大型的数据量,就不要用他,影响插入速度
7、mysql 5.6支持explain update/delete
mysql> explain update update_log_test set msg='gugu' where id=4;
+----+-------------+-----------------+-------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------------+-------+---------------+---------+---------+-------+------+-------------+
| 1 | SIMPLE | update_log_test | range | PRIMARY | PRIMARY | 4 | const | 1 | Using where |
+----+-------------+-----------------+-------+---------------+---------+---------+-------+------+-------------+
1 row in set (0.01 sec)
mysql> explain delete from update_log_test where id=4;
+----+-------------+-----------------+-------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------------+-------+---------------+---------+---------+-------+------+-------------+
| 1 | SIMPLE | update_log_test | range | PRIMARY | PRIMARY | 4 | const | 1 | Using where |
+----+-------------+-----------------+-------+---------------+---------+---------+-------+------+-------------+
1 row in set (0.00 sec)
8、mysql5.6优化了合并索引
mysql> explain select * from update_log where date='2014-11-12' or time='14:00:00';
+----+-------------+------------+-------------+---------------+-------------+---------+------+----------+---------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------------+---------------+-------------+---------+------+----------+---------------------------------------+
| 1 | SIMPLE | update_log | index_merge | date,i_time | date,i_time | 4,4 | NULL | 10808103 | Using union(date,i_time); Using where |
+----+-------------+------------+-------------+---------------+-------------+---------+------+----------+---------------------------------------+
1 row in set (0.01 sec)
mysql> explain select * from update_log where date='2014-11-12' union select * from update_log where time='14:00:00';
+----+--------------+------------+------+---------------+--------+---------+-------+----------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------+------------+------+---------------+--------+---------+-------+----------+-----------------------+
| 1 | PRIMARY | update_log | ref | date | date | 4 | const | 10807697 | NULL |
| 2 | UNION | update_log | ref | i_time | i_time | 4 | const | 406 | Using index condition |
| NULL | UNION RESULT | <union1,2> | ALL | NULL | NULL | NULL | NULL | NULL | Using temporary |
+----+--------------+------------+------+---------------+--------+---------+-------+----------+-----------------------+
3 rows in set (0.00 sec)
实际测试2条sql,or的执行时间是union执行时间的两倍。
1、union all 不一定就比 or及in 快,要结合实际情况分析到底使用哪种情况。
2、对于索引列来最好使用union all,因复杂的查询【包含运算等】将使or、in放弃索引而全表扫描,除非你能确定or、in会使用索引。
3、对于只有非索引字段来说你就老老实实的用or 或者in,因为 非索引字段本来要全表扫描而union all 只成倍增加表扫描的次数。
Union:对两个结果集进行并集操作,不包括重复行,同时进行默认规则的排序;Union All:对两个结果集进行并集操作,包括重复行,不进行排序;
union因为要进行重复值扫描,所以效率低。
that's all
欢迎与我交流 tina QQ:906179271
发表评论
-
mysql设置外键约束on delete cascade on update cascade
2016-12-09 16:27 3733mysql设置外键约束on delet ... -
mysql权限管理(实例)
2016-05-10 17:21 1514mysql权限管理实例 本文并没有很详细的介绍对具体的对象授 ... -
mysql简单的碎片清理脚本
2016-05-10 16:52 1496mysql简单的碎片清理脚本 #!/bin/bash date ... -
mysql qpress压缩备份恢复
2016-05-03 16:30 6963说明: 1.前面博客已经介绍过gzip压缩方法,备份正常,但后 ... -
mysql xtrabackup在线搭建主从
2016-04-11 14:59 1951使用xtrabackup进行在线的主从搭建: [root@m ... -
mysql xtrabackup在线备份还原(全备+增备)
2016-04-11 14:47 1053工具安装: [root@mysqlserver var]# t ... -
mysql主库清理数据,从库保留
2016-04-01 15:26 1298因为业务需要,想在mysql主库清理一些数据,但从库想要保留, ... -
oracle,postgresql,mysql一些使用上的区别记录
2015-12-16 11:38 01.限制行数: select * from ta where ... -
mysql 安装-tina
2015-12-08 17:32 0mysql安装-tina 1、准备安装程序(http://ww ... -
mysqldump 只导入数据或只导结构
2015-12-22 10:36 2721[size=small]mysqldump只导出数据或只导出表 ... -
mysql server has gone away
2015-12-10 09:26 878mysql server has gone away,他的意思 ... -
mysql optimize 清理碎片
2015-12-09 09:26 1207---定期清理脚本 0 1 * * 4 root /root ... -
mysql binlog
2015-12-10 09:26 1346mysqld在每个二进制日志 ... -
mysql远程连接设置
2015-12-10 09:25 1009远程连接mysql数据库: 连接上以后,通过这台跳转服务器远 ... -
Last_SQL_Error: Error 'Duplicate entry '1' for key 'PRIMARY''
2015-12-10 09:25 1722[size=small]-实际遇到的问题: Last_SQL ... -
[ERROR] Slave I/O: error connecting to master
2015-12-09 09:26 8214刚配置的MySQL主从,在从机上看到 点击(此处)折叠或打开 ... -
MySQL常用函数
2015-02-05 10:34 539一、字符串类 1、left(str, length) 从左开始 ... -
MySQL触发器简介
2015-02-05 10:33 900一、触发器基本语法 CREATE TRIGGER trigge ... -
MySQL主从切换
2015-02-05 10:32 506环境: 原主库:192.168.10.197 ---新 ... -
MySQL主从搭建
2015-02-05 10:31 797环境简介 master(主):192.168.12.101 s ...
相关推荐
还有数据库管理工具,如MySQL Workbench或Oracle SQL Developer,它们提供了丰富的功能,包括数据库设计、数据导入导出、备份恢复以及性能调优等。 文件"数据库管理系统资源的生产者-消费者层次结构.vsd"可能是一个...
以上这些只是数据库性能调优的部分内容,实际操作中还需要结合具体的数据库管理系统(如MySQL、Oracle、SQL Server等)和业务需求来进行细致的调整。通过对这些原理和技术的深入理解和应用,可以有效地提升数据库...
### 数据库性能调优——原理与技术 #### 一、基础知识与重要概念 **1.1 数据库性能调优概述** 数据库性能调优是确保数据库系统高效稳定运行的关键环节之一。它不仅涉及到对数据库本身的调整,还包括对底层硬件、...
【MySQL面试题】在面试MySQL相关的职位时,面试官可能会问到一系列关于数据库基础、SQL语法、事务处理、索引优化以及性能调优的问题。以下是一些可能的面试重点: 1. **数据库基本概念**: - 数据库是用于存储和...
### MySQL数据库调优技术大全 #### 一、数据库与关系代数 - **关系代数基础**:在进行MySQL查询优化之前,理解关系代数的基本概念是非常重要的。关系代数是一种用于描述关系数据库操作的形式语言,它可以帮助我们...
Oracle数据库是全球领先的商业数据库系统,"精通Oracle 9i(PDG)"可能涵盖了Oracle 9i版本的全部功能和使用技巧,包括数据库安装、配置、数据模型、SQL与PL/SQL编程、事务处理、备份恢复、性能调优等主题。...
本篇将围绕“MySQL高性能—数据库的性能调优”这一主题,深入探讨如何优化MySQL的性能,提升系统整体效率。 首先,性能优化主要涉及以下几个方面: 1. **查询优化**:高效的SQL查询是性能提升的关键。这包括避免全...
- 数据库调优 10. 安全: - XSS、CSRF、SQL注入等常见安全漏洞 - Spring Security安全框架 以上是Java后端必会的所有技能,掌握这些技能可以帮助开发人员在Java后端开发领域更加得心应手。
MySQL数据库调优是一个复杂而重要的任务,涉及到多个层面的优化策略。以下是一些关键的调优建议: 1. **字段宽度最小化**:减少字段宽度可以显著降低存储需求,进而节省磁盘空间和提高查询效率。例如,如果一个字段...
### 数据库调优原理及方法 #### 一、引言 在当今数据驱动的时代背景下,数据库作为信息系统的核心组件,其性能直接影响着整个系统的稳定性和效率。数据库调优是指通过一系列的技术手段来提升数据库的性能,使得...
总的来说,tpch-mysql-master是MySQL性能调优过程中不可或缺的工具,它可以帮助我们更好地理解和优化数据库系统,确保在复杂业务场景下,MySQL能提供稳定且高效的服务。无论你是数据库管理员还是开发人员,都应该...
【主 题】 MySQL调优技术 【主要内容】B+树介绍、单表性能调优、多表性能调优以及SQL语句效率对比。 【应用场景】1、B+树作为MySQL索引底层实现的数据结构,需要我们了解其工作机制; 2、从创建表要注意的点以及SQL...
通过对MySQL的深入测试,我们可以更好地理解其在高并发、大数据量环境下的行为,为数据库的选型、调优提供有力支持。 总结来说,tpcc-mysql是评估和优化MySQL OLTP性能的重要工具,通过遵循TPC-C标准的测试,我们...
8. **结果分析**:收集到测试结果后,分析各项性能指标,对比不同配置或版本的MySQL,找出性能瓶颈并进行调优。 9. **安全与维护**:在生产环境中,确保tpcc-mysql遵循最佳实践,如定期备份、权限管理、日志监控和...
8. **性能监控与调优**:了解如何使用SHOW STATUS、SHOW VARIABLES、SHOW ENGINE INNODB STATUS等命令来监控数据库状态。掌握使用慢查询日志来找出性能瓶颈,并通过调整参数或优化查询语句来提升性能。 9. **数据库...
高性能可扩展mysql Mysql视频教程 mongodb视频教程 oracle视频教程, ...主要讲解了以上三种当前主流数据库的高级知识,侧重于数据库调优的高级技能,对于开发高性能/并发网站的学习朋友应该有所帮助。