Mysql查询优化的一些实用方法总结

目录
  • 1. count的优化
  • 2. 避免使用不兼容的数据类型。
  • 3. 索引字段上进行运算会使索引失效。
  • 4. 避免使用!=或<>、IS NULL或IS NOT NULL、IN ,NOT IN等这样的操作符.
  • 5. 尽量使用数字型字段.
  • 6. 合理使用EXISTS,NOT EXISTS子句。如下所示:
  • 7. 能够用BETWEEN的就不要用IN
  • 8. 能够用DISTINCT的就不用GROUP BY
  • 9. 尽量不要用SELECT INTO语句。
  • 10. 必要时强制查询优化器使用某个索引
  • 11. 消除对大型表行数据的顺序存取
  • 12. 尽量避免在索引过的字符数据中,使用非打头字母搜索。这也使得引擎无法利用索引。
  • 13. 虽然UPDATE、DELETE语句的写法基本固定,但是还是对UPDATE语句给点建议:
  • 14. 能用UNION ALL就不要用UNION
  • 15. 字段数据类型优化:
  • 16. 关于大数据量limit分布的优化见下面链接(当偏移量特别大时,limit效率会非常低):
  • 17. 程序中如果一次性对同一个表插入多条数据,比如以下语句:
  • 18. 不要在选择的栏位上放置索引,这是无意义的。
  • 19. ORDER BY语句的MySQL优化:
  • 总结

指标:执行时间 检查的行数 返回的行数

1. count的优化

比如:计算id大于5的城市 a. select count(*) from world.city where id > 5; b. select (select count(*) from world.city) – count(*) from world.city where id <= 5; a语句当行数超过11行的时候需要扫描的行数比b语句要多, b语句扫描了6行,此种情况下,b语句比a语句更有效率。当没有where语句的时候直接select count(*) from world.city这样会更快,因为mysql总是知道表的行数。

案例:

# 建库
CREATE DATABASE IF NOT EXISTS db3 DEFAULT CHARSET=utf8;
USE db3;
# 建表
CREATE TABLE IF NOT EXISTS cnt(id INT , NAME VARCHAR(10),age INT ,tel VARCHAR(10));
# 创建存储过程 procedrue
DELIMITER $
CREATE PROCEDURE cnt()
BEGIN
#定义变量 declare
DECLARE i INT DEFAULT 0;
WHILE(i<100000) DO
    BEGIN
        SELECT i;
        SET i=i+1;
        INSERT INTO cnt(id,NAME)VALUES(i,'zs');
    END;
END WHILE;
END $
DELIMITER ;
#调用存储过程
CALL cnt();

SELECT COUNT(*)FROM cnt;
#执行耗时   : 0 sec 传送时间   : 0.051 sec 总耗时      : 0.051 sec
#数据库知道表内有多少条数据    

SELECT COUNT(*) FROM cnt WHERE id > 5;
# 执行耗时   : 0.130 sec 传送时间   : 0 sec 总耗时      : 0.130 sec
# 使用where 扫描了全表 id > 5的所有数据 总查询99995条

SELECT (SELECT COUNT(*) FROM cnt) - COUNT(*) FROM cnt WHERE id <=5 ;
# 执行耗时   : 0.080 sec 传送时间   : 0 sec  总耗时      : 0.081 sec
# 使用where 扫描全表 id <= 5 的五条数据  加上 (SELECT COUNT(*) FROM cnt) 一条数据 总查询 6 条

2. 避免使用不兼容的数据类型。

例如float和int、char和varchar、binary和varbinary是不兼容的。数据类型的不兼容可能使优化器无法执行一些本来可以进行的优化操作。 在程序中,保证在实现功能的基础上,尽量减少对数据库的访问次数;通过搜索参数,尽量减少对表的访问行数,最小化结果集,从而减轻网络负担;

能够分开的操作尽量分开处理,提高每次的响应速度;

在数据窗口使用SQL时,尽量把使用的索引放在选择的首列;算法的结构尽量简单;在查询时,不要过多地使用通配符如 SELECT * FROM T1语句,要用到几列就选择几列如:SELECT COL1,COL2 FROM T1;

在可能的情况下尽量限制尽量结果集行数如:SELECT TOP 300 COL1,COL2,COL3 FROM T1,因为某些情况下用户是不需要那么多的数据的。不要在应用中使用数据库游标,游标是非常有用的工具,但比使用常规的、面向集的SQL语句需要更大的开销;按照特定顺序提取数据的查找。

案例:

# 创建一个表测试了一下 int 类型数据插入float类型的数据  结果:插入数度变慢 会四舍五入
CREATE TABLE sss(id INT);
INSERT INTO sss VALUES(12.4);
INSERT INTO sss VALUES(12.5);

3. 索引字段上进行运算会使索引失效。

尽量避免在WHERE子句中对字段进行函数或表达式操作,这将导致引擎放弃使用索引而进行全表扫描。

如:SELECT * FROM T1 WHERE F1/2=100 应改为: SELECT * FROM T1 WHERE F1=100*2

案例:

#创建索引
CREATE INDEX index_id ON cnt(id);

SELECT * FROM cnt WHERE id > 50000;
#行耗时   : 0.009 sec  传送时间   : 0 sec  总耗时      : 0.010 sec
SELECT * FROM cnt WHERE id*2 > 100000;
#执行耗时   : 0.031 sec 传送时间   : 0 sec  总耗时      : 0.032 sec
# 使用了索引进行运算  使得索引失效 效率变慢了

4. 避免使用!=或<>、IS NULL或IS NOT NULL、IN ,NOT IN等这样的操作符.

因为这会使系统无法使用索引,而只能直接搜索表中的数据。例如: SELECT id FROM employee WHERE id != “B%” 优化器将无法通过索引来确定将要命中的行数,因此需要搜索该表的所有行。在in语句中能用exists语句代替的就用exists.

5. 尽量使用数字型字段.

一部分开发人员和数据库管理人员喜欢把包含数值信息的字段 设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接回逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。

6. 合理使用EXISTS,NOT EXISTS子句。如下所示:

SELECT SUM(T1.C1) FROM T1 WHERE (SELECT COUNT(*)FROM T2 WHERE T2.C2=T1.C2>0) 2.SELECT SUM(T1.C1) FROM T1WHERE EXISTS(SELECT * FROM T2 WHERE T2.C2=T1.C2) 两者产生相同的结果,但是后者的效率显然要高于前者。

因为后者不会产生大量锁定的表扫描或是索引扫描。如果你想校验表里是否存在某条纪录,不要用count(*)那样效率很低,而且浪费服务器资源。可以用EXISTS代替。如:IF (SELECT COUNT(*) FROM table_name WHERE column_name = ‘xxx’)

可以写成:IF EXISTS (SELECT * FROM table_name WHERE column_name = ‘xxx’)

7. 能够用BETWEEN的就不要用IN

8. 能够用DISTINCT的就不用GROUP BY

9. 尽量不要用SELECT INTO语句。

SELECT INTO 语句会导致表锁定,阻止其他用户访问该表。

10. 必要时强制查询优化器使用某个索引

SELECT * FROM T1 WHERE nextprocess = 1 AND processid IN (8,32,45)

改成: SELECT * FROM T1 (INDEX = IX_ProcessID) WHERE nextprocess = 1 AND processid IN (8,32,45)

则查询优化器将会强行利用索引IX_ProcessID 执行查询。

案例:

# 10.必要时强制查询优化器使用索引
#建表
create table if not exists T1(processid int, nextprocess int);
#建索引
create index index_processID on T1(processid);
# 10.1:不使用索引
select * from T1 where nextprocess = 1 and processid in (8,32,45);
# 10.2: 强制使用索引
select * from T1 froce index(index_processID)
 where nextprocess = 1 and process = 1 and processid in (8,32,45);

11. 消除对大型表行数据的顺序存取

尽管在所有的检查列上都有索引,但某些形式的WHERE子句强迫优化器使用顺序存取。如: SELECT * FROM orders WHERE (customer_num=104 AND order_num>1001) OR order_num=1008 解决办法可以使用并集来避免顺序存取: SELECT * FROM orders WHERE customer_num=104 AND order_num>1001 UNION SELECT * FROM orders WHERE order_num=1008 这样就能利用索引路径处理查询。【jacking 数据结果集很多,但查询条件限定后结果集不大的情况下,后面的语句快】

案例:

# 11.消除对大型表 行数据的顺序存取
#建表
create table if not exists orders(customer_num int, order_num int);
# 消除顺序索引
#11.1 没有使用索引
select * from orders where (customer_num=104 and order_num > 100) or order_num=1005;
#11.2 使用索引  将or 拆开 避免使用or
select * from orders where custoner_num = 104 and order_num > 100
union  # union 默认去重,排序   union all 不去重,不会排序
select * from orders where order_num=1005;

12. 尽量避免在索引过的字符数据中,使用非打头字母搜索。这也使得引擎无法利用索引。

见如下例子: SELECT * FROM T1 WHERE NAME LIKE ‘%L%’ SELECT * FROM T1 WHERE SUBSTING(NAME,2,1)=’L’ SELECT * FROM T1 WHERE NAME LIKE ‘L%’ 即使NAME字段建有索引,前两个查询依然无法利用索引完成加快操作,引擎不得不对全表所有数据逐条操作来完成任务。而第三个查询能够使用索引来加快操作,不要习惯性的使用 ‘%L%’这种方式(会导致全表扫描),如果可以使用`L%’相对来说更好;

案例:

# 12. 模糊查询where like ,字母打头'1%' 会使用索引 即%在右
create table if not exists T2(name varchar(20));
create index  index_name on T2(name);
# 12.1 不会使用索引
select * from T2 where name like '%L%';
select * from T2 where name like '%L';
    #substring 进行字符串截取 参数:字符串,起始位置,结束位置
select * from T2 where substring(name,2,1)='L';
# 12.2 使用到索引
select * from T2 where name like 'L%';

13. 虽然UPDATE、DELETE语句的写法基本固定,但是还是对UPDATE语句给点建议:

a) 尽量不要修改主键字段。 b) 当修改VARCHAR型字段时,尽量使用相同长度内容的值代替。 c) 尽量最小化对于含有UPDATE触发器的表的UPDATE操作。 d) 避免UPDATE将要复制到其他数据库的列。 e) 避免UPDATE建有很多索引的列。 f) 避免UPDATE在WHERE子句条件中的列。

14. 能用UNION ALL就不要用UNION

UNION ALL不执行SELECT DISTINCT函数,这样就会减少很多不必要的资源 在跨多个不同的数据库时使用UNION是一个有趣的优化方法,UNION从两个互不关联的表中返回数据,这就意味着不会出现重复的行,同时也必须对数据进行排序,我们知道排序是非常耗费资源的,特别是对大表的排序。 UNION ALL可以大大加快速度,如果你已经知道你的数据不会包括重复行,或者你不在乎是否会出现重复的行,在这两种情况下使用UNION ALL更适合。此外,还可以在应用程序逻辑中采用某些方法避免出现重复的行,这样UNION ALL和UNION返回的结果都是一样的,但UNION ALL不会进行排序。

15. 字段数据类型优化:

a. 避免使用NULL类型:NULL对于大多数数据库都需要特殊处理,MySQL也不例外,它需要更多的代码,更多的检查和特殊的索引逻辑,有些开发人员完全没有意识到,创建表时NULL是默认值,但大多数时候应该使用NOT NULL,或者使用一个特殊的值,如0,-1作为默认值。 b. 尽可能使用更小的字段,MySQL从磁盘读取数据后是存储到内存中的,然后使用cpu周期和磁盘I/O读取它,这意味着越小的数据类型占用的空间越小,从磁盘读或打包到内存的效率都更好,但也不要太过执着减小数据类型,要是以后应用程序发生什么变化就没有空间了。修改表将需要重构,间接地可能引起代码的改变,这是很头疼的问题,因此需要找到一个平衡点。 c. 优先使用定长型

16. 关于大数据量limit分布的优化见下面链接(当偏移量特别大时,limit效率会非常低):

http://ariyue.iteye.com/blog/553541 附上一个提高limit效率的简单技巧,在覆盖索引(覆盖索引用通俗的话讲就是在select的时候只用去读取索引而取得数据,无需进行二次select相关表)上进行偏移,而不是对全行数据进行偏移。可以将从覆盖索引上提取出来的数据和全行数据进行联接,然后取得需要的列,会更有效率,看看下面的查询: mysql> select film_id, description from sakila.film order by title limit 50, 5; 如果表非常大,这个查询最好写成下面的样子: mysql> select film.film_id, film.description from sakila.film inner join(select film_id from sakila.film order by title liimit 50,5) as film usinig(film_id);

17. 程序中如果一次性对同一个表插入多条数据,比如以下语句:

insert into person(name,age) values(‘xboy’, 14); insert into person(name,age) values(‘xgirl’, 15); insert into person(name,age) values(‘nia’, 19); 把它拼成一条语句执行效率会更高. insert into person(name,age) values(‘xboy’, 14), (‘xgirl’, 15),(‘nia’, 19);

18. 不要在选择的栏位上放置索引,这是无意义的。

应该在条件选择的语句上合理的放置索引,比如where,order by。

SELECT id,title,content,cat_id FROM article WHERE cat_id = 1;

19. ORDER BY语句的MySQL优化:

a. ORDER BY + LIMIT组合的索引优化。

如果一个SQL语句形如:

SELECT [column1],[column2],…. FROM [TABLE] ORDER BY [sort] LIMIT [offset],[LIMIT];

这个SQL语句优化比较简单,在[sort]这个栏位上建立索引即可。

b. WHERE + ORDER BY + LIMIT组合的索引优化,形如:

SELECT [column1],[column2],…. FROM [TABLE] WHERE [columnX] = [VALUE] ORDER BY [sort] LIMIT [offset],[LIMIT];

这个语句,如果你仍然采用第一个例子中建立索引的方法,虽然可以用到索引,但是效率不高。更高效的方法是建立一个联合索引(columnX,sort)

c. WHERE + IN + ORDER BY + LIMIT组合的索引优化,形如:

SELECT [column1],[column2],…. FROM [TABLE] WHERE [columnX] IN ([value1],[value2],…) ORDER BY [sort] LIMIT [offset],[LIMIT];

这个语句如果你采用第二个例子中建立索引的方法,会得不到预期的效果(仅在[sort]上是using index,WHERE那里是using where;using filesort),理由是这里对应columnX的值对应多个。 目前哥还木有找到比较优秀的办法,等待高手指教。

d.WHERE+ORDER BY多个栏位+LIMIT,比如:

SELECT * FROM [table] WHERE uid=1 ORDER x,y LIMIT 0,10;

对于这个语句,大家可能是加一个这样的索引:(x,y,uid)。但实际上更好的效果是(uid,x,y)。这是由MySQL处理排序的机制造成的。

总结

到此这篇关于Mysql查询优化的一些实用方法的文章就介绍到这了,更多相关Mysql查询优化内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 提升MYSQL查询效率的10个SQL语句优化技巧

    MySQL数据库执行效率对程序的执行速度有很大的影响,有效的处理优化数据库是非常有用的.尤其是大量数据需要处理的时候. 1. 优化你的MySQL查询缓存 在MySQL服务器上进行查询,可以启用高速查询缓存.让数据库引擎在后台悄悄的处理是提高性能的最有效方法之一.当同一个查询被执行多次时,如果结果是从缓存中提取,那是相当快的. 但主要的问题是,它是那么容易被隐藏起来以至于我们大多数程序员会忽略它.在有些处理任务中,我们实际上是可以阻止查询缓存工作的. // query cache does NOT

  • mysql优化limit查询语句的5个方法

    mysql的分页比较简单,只需要limit offset,length就可以获取数据了,但是当offset和length比较大的时候,mysql明显性能下降 1.子查询优化法 先找出第一条数据,然后大于等于这条数据的id就是要获取的数据 缺点:数据必须是连续的,可以说不能有where条件,where条件会筛选数据,导致数据失去连续性,具体方法请看下面的查询实例: 复制代码 代码如下: mysql> set profiling=1; Query OK, 0 rows affected (0.00

  • 大幅优化MySQL查询性能的奇技淫巧

    回顾 MySQL / InnoDB 的改善历史.你能很容易发现.在MySQL 5.6稳定版本中从来没有在read-only 这么快的提速,它很容易搞懂,以及在read-only(RO)有着良好的扩张性.也很期待它在read+write(RW)上达到一个较高水平.(特别是在读取数据是数据库主要工作的时候) 然而.我们对于RO在 MySQL 5.6的表现也十分的高兴,在5.7这个版本中,主要工作集中在 read+write (RW)上, 因为在大数据的处理上还没能达到我们的期望.但是RW依赖RO下.

  • 详解Mysql多表联合查询效率分析及优化

    1. 多表连接类型 1. 笛卡尔积(交叉连接) 在MySQL中可以为CROSS JOIN或者省略CROSS即JOIN,或者使用','  如: SELECT * FROM table1 CROSS JOIN table2 SELECT * FROM table1 JOIN table2 SELECT * FROM table1,table2 由于其返回的结果为被连接的两个数据表的乘积,因此当有WHERE, ON或USING条件的时候一般不建议使用,因为当数据表项目太多的时候,会非常慢.一般使用LE

  • Mysql查询最近一条记录的sql语句(优化篇)

    下策--查询出结果后将时间排序后取第一条 select * from a where create_time<="2017-03-29 19:30:36" order by create_time desc limit 1 这样做虽然可以取出当前时间最近的一条记录,但是一次查询需要将表遍历一遍,对于百万以上数据查询将比较费时:limit是先取出全部结果,然后取第一条,相当于查询中占用了不必要的时间和空间:还有如果需要批量取出最近一条记录,比方说:"一个订单表,有用户,订

  • 浅谈MySQL中优化sql语句查询常用的30种方法

    1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描. 3.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如: select id from t where num is null 可以在num上设置默认值0,确保表中num列没有null值,然后这样查询: select id from

  • MySQL查询优化之explain的深入解析

    在分析查询性能时,考虑EXPLAIN关键字同样很管用.EXPLAIN关键字一般放在SELECT查询语句的前面,用于描述MySQL如何执行查询操作.以及MySQL成功返回结果集需要执行的行数.explain 可以帮助我们分析 select 语句,让我们知道查询效率低下的原因,从而改进我们查询,让查询优化器能够更好的工作. 一.MySQL 查询优化器是如何工作的MySQL 查询优化器有几个目标,但是其中最主要的目标是尽可能地使用索引,并且使用最严格的索引来消除尽可能多的数据行.最终目标是提交 SEL

  • Mysql使用索引实现查询优化

    索引的目的在于提高查询效率,可以类比字典,如果要查"mysql"这个单词,我们肯定需要定位到m字母,然后从下往下找到y字母,再找到剩下的sql.如果没有索引,那么你可能需要把所有单词看一遍才能找到你想要的. 1.索引的优点 假设你拥有三个未索引的表t1.t2和t3,每个表都分别包含数据列i1.i2和i3,并且每个表都包含了1000条数据行,其序号从1到1000.查找某些值匹配的数据行组合的查询可能如下所示: SELECT t1.i1, t2.i2, t3.i3 FROM t1, t2,

  • mysql嵌套查询和联表查询优化方法

    嵌套查询糟糕的优化在上面我提到过,不考虑特殊的情况,联表查询要比嵌套查询更有效.尽管两条查询表达的是同样的意思,尽管你的计划是告诉服务器要做什么,然后让它决定怎么做,但有时候你非得告诉它改怎么做.否则优化器可能会做傻事.我最近就碰到这样的情况.这几个表是三层分级关系:category, subcategory和item.有几千条记录在category表,几百条记录在subcategory表,以及几百万条在item表.你可以忽略category表了,我只是交代一下背景,以下查询语句都不涉及到它.这

  • mysql in语句子查询效率慢的优化技巧示例

    表结构如下,文章只有690篇. 文章表article(id,title,content) 标签表tag(tid,tag_name) 标签文章中间表article_tag(id,tag_id,article_id) 其中有个标签的tid是135,查询标签tid是135的文章列表. 690篇文章,用以下的语句查询,奇慢: select id,title from article where id in( select article_id from article_tag where tag_id=

随机推荐