update多个字段语句_MYSQL查询语句优化
mysql的性能优化包罗甚⼴: 索引优化,查询优化,查询缓存,服务器设置优化,操作系统和硬件优化,应⽤层⾯优化(web服务器,缓存)等等。这⾥的记录的优化技巧更适⽤于开发⼈员,都是从⽹络上收集和⾃⼰整理的,主要是查询语句上⾯的优化,其它层⾯的优化技巧在此不做记录。
1. 查询的开销指标:
执⾏时间 检查的⾏数 返回的⾏数
1. 建⽴索引的⼏个准则:
1、合理的建⽴索引能够加速数据读取效率,不合理的建⽴索引反⽽会拖慢数据库的响应速度。
2、索引越多,更新数据的速度越慢。
3、尽量在采⽤MyIsam作为引擎的时候使⽤索引(因为MySQL以BTree存储索引),⽽不是InnoDB。但MyISAM不⽀持Transcation。
4、当你的程序和数据库结构/SQL语句已经优化到⽆法优化的程度,⽽程序瓶颈并不能顺利解决,那就是应该考虑使⽤诸如
memcached这样的分布式缓存系统的时候了。
5、习惯和强迫⾃⼰⽤EXPLAIN来分析你SQL语句的性能。
§优化技巧
§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总是知道表的⾏数。
§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语句需要更⼤的开销;按照特定顺序提取数据的查。
§3. 索引字段上进⾏运算会使索引失效。
尽量避免在WHERE⼦句中对字段进⾏函数或表达式操作,这将导致引擎放弃使⽤索引⽽进⾏全表扫描。如:
1SELECT * FROM T1 WHERE F1/2=100 应改为: SELECT * FROM T1 WHERE F1=100*2
§4. 避免使⽤!=或<>、IS NULL或IS NOT NULL、IN ,NOT IN等这样的操作符.
因为这会使系统⽆法使⽤索引,⽽只能直接搜索表中的数据。例如:
SELECT id FROM employee WHERE id != “B%”
优化器将⽆法通过索引来确定将要命中的⾏数,因此需要搜索该表的所有⾏。在in语句中能⽤exists语句代替的就⽤exists.
§5. 尽量使⽤数字型字段.
unionpay international app singapore⼀部分开发⼈员和数据库管理⼈员喜欢把包含数值信息的字段 设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是
因为引擎在处理查询和连接回逐个⽐较字符串中每⼀个字符,⽽对于数字型⽽⾔只需要⽐较⼀次就够了。
§6. 合理使⽤EXISTS,NOT EXISTS⼦句。如下所⽰:
SELECT SUM(T1.C1) FROM T1 WHERE (SELECT COUNT(*)FROM T2 WHERE T2.C2=T1.C2>0)SELECT SUM(T1.C1) FROM T1WHERE EXISTS(SELECT * FR
mysql语句分类两者产⽣相同的结果,但是后者的效率显然要⾼于前者。因为后者不会产⽣⼤量锁定的表扫描或是索引扫描。如果你想校验表⾥是否
存在某条纪录,不要⽤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 执⾏查询。
§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 数据结果集很多,但查询条件限定后结果集不⼤的情况下,后⾯的语句快】
§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%’相对来说更好;
§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效率会⾮常低):
附上⼀个提⾼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;
上⾯这个语句,你在id/title/content上放置索引是毫⽆意义的,对这个语句没有任何优化作⽤。但是如果你在外键cat_id上放置⼀个索引,那作⽤就相当⼤了。
§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];零基础入门学习c语言教程
这个语句如果你采⽤第⼆个例⼦中建⽴索引的⽅法,会得不到预期的效果(仅在[sort]上是using index,WHERE那⾥是using where;using filesort),理由是这⾥对应columnX的值对应多个。 ⽬前哥还⽊有到⽐较优秀的办法,等待⾼⼿指教。
d.WHERE+ORDER BY多个栏位+LIMIT,⽐如:c sscanf
SELECT * FROM [table] WHERE uid=1 ORDER x,y LIMIT 0,10;
对于这个语句,⼤家可能是加⼀个这样的索引:(x,y,uid)。但实际上更好的效果是(uid,x,y)。这是由MySQL处理排序的机制造成的。
§20. 其它技巧:
参考1
参考2
golang未来发展趋势
参考3
参考4
参考5
最后,你可以使⽤explain关键字去判断和评测⼀个sql语句是否还有优化的可能性,关于它的详细使⽤请参考mysql⼿册。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。