Mysql_查询优化_刘益长
一、 count优化
#创建表 CREATE TABLE IF NOT EXISTS cnt ( id INT, NAME VARCHAR(10), age INT, tel VARCHAR(10) ); #创建存储过程 DELIMITER $ CREATE PROCEDURE cnt() BEGIN #定义一个循坏变量 DECLARE i INT DEFAULT 0; WHILE(i<1000) DO BEGIN SELECT i; SET i=i+1; INSERT INTO cnt(id,NAME)VALUES(i,"zhang"); END; END WHILE; END $ DELIMITER ; #调用存储过程 CALL cnt(); #查询语句a SELECT COUNT(*) FROM cnt WHERE id > 5; #查询语句b SELECT (SELECT COUNT(*) FROM cnt) - COUNT(*) FROM cnt WHERE id <= 5;
语句当行数超过11行的时候需要扫描的行数比b语句要多, b语句扫描了6行,此种情况下,b语句比a语句更有效率。当没有where语句的时候直接select count(*) from world.city这样会更快,因为mysql总是知道表的行数。
二、 避免使用不兼容的数据类型。
例如float和int、char和varchar、binary和varbinary是不兼容的。数据类型的不兼容可能使优化器无法执行一些本来可以进行的优化操作。在程序中,保证在实现功能的基础上,尽量减少对数据库的访问次数;通过搜索参数,尽量减少对表的访问行数,最小化结果集,从而减轻网络负担;能够分开的操作尽量分开处理,提高每次的响应速度;在数据窗口使用SQL时,尽量把使用的索引放在选择的首列;算法的结构尽量简单;在查询时,不要过多地使用通配符如 SELECT * FROM T1语句,要用到几列就选择几列如:SELECT COL1,COL2 FROM T1;在可能的情况下尽量限制尽量结果集行数如:SELECT TOP 300 COL1,COL2,COL3 FROM T1,因为某些情况下用户是不需要那么多的数据的。不要在应用中使用数据库游标,游标是非常有用的工具,但比使用常规的、面向集的SQL语句需要更大的开销;按照特定顺序提取数据的查找
#数据不兼容会拉低效率 INSERT INTO cnt(id)VALUES(12.3);
三、索引字段上进行运算会使索引失效
尽量避免在WHERE子句中对字段进行函数或表达式操作,这将导致引擎放弃使用索引而进行全表扫描
#索引列进行运算会让索引失效 CREATE INDEX index_age ON cnt(age); SELECT * FROM cnt WHERE age > 18; SELECT * FROM cnt WHERE age * 2 > 36; CREATE INDEX index_age ON cnt(id); SELECT * FROM cnt WHERE id > 10000; SELECT * FROM cnt WHERE id * 2 > 20000;
四、避免使用!=或<>、IS NULL或IS NOT NULL、IN ,NOT IN等这样的操作符.
因为这会使系统无法使用索引,而只能直接搜索表中的数据。例如: SELECT id FROM employee WHERE id != “B%”
优化器将无法通过索引来确定将要命中的行数,因此需要搜索该表的所有行。在in语句中能用exists语句代替的就用exists.
#创建表 CREATE TABLE IF NOT EXISTS emp ( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(10), age INT, tel VARCHAR(10) ); #创建存储过程 DELIMITER $ CREATE PROCEDURE emp() BEGIN #定义一个循坏变量 DECLARE i INT DEFAULT 0; WHILE(i<1000) DO BEGIN SELECT i; SET i=i+1; INSERT INTO emp(NAME,age)VALUES("zhang",i); END; END WHILE; END $ DELIMITER ; # 调用存储过程 CALL emp(); SELECT * FROM emp; # 避免的情况 !=, <>, is null, is not null, in, not in SELECT COUNT(*) FROM emp WHERE age IN (SELECT age FROM emp WHERE id > 100); SELECT COUNT(*) FROM emp WHERE EXISTS (SELECT age FROM emp WHERE id > 100);
五、尽量使用数字型字段.
一部分开发人员和数据库管理人员喜欢把包含数值信息的字段 设计为字符型,这会降低查询和连接的性能,并会增加存储开销。
这是因为引擎在处理查询和连接回逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。
# 尽量使用数字型字段 CREATE TABLE IF NOT EXISTS t1 (c1 INT,c2 INT); CREATE TABLE IF NOT EXISTS t2 (c1 INT,c2 INT);
六、合理使用EXISTS,NOT EXISTS子句。
# 使用where > 0; SELECT SUM(t1.c1) FROM t1 WHERE (SELECT COUNT(*) FROM t2 WHERE t2.c2=t1.c2 > 0); # 使用exists SELECT SUM(t1.c1) FROM t1 WHERE EXISTS (SELECT COUNT(*) FROM t2 WHERE t2.c2=t1.c2);
七、能够用BETWEEN的就不要用IN ,能够用DISTINCT的就不用GROUP BY
# between 是连续的范围,使用索引 SELECT * FROM emp WHERE age BETWEEN 100 AND 200; # in不连续的范围,不能使用索引 SELECT * FROM emp WHERE age IN (100,150,200); # distinct去重:重复的数据取一个 SELECT DISTINCT NAME FROM emp; # group by分组 SELECT NAME FROM emp GROUP BY NAME;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?