但是从性能上来看,第二条语句写法效率更高 。原因有两个:
- 使用GROUP BY子句聚合时会进行排序,如果事先通过WHERE子句筛选出一部分行,就能够减轻排序的负担 。
- 在WHERE子句的条件里可以使用索引 。HAVING子句是针对聚合后生成的视图进行筛选的,但是很多时候聚合后的视图都没有继承原表的索引结构 。
SELECT * FROM SomeTable WHERE col_1 = 10; -- 走了索引SELECT * FROM SomeTable WHERE col_1 ='10'; -- 没走索引SELECT * FROM SomeTable WHERE col_1 = CAST(10, AS CHAR(2)); -- 走了索引
当查询条件左边和右边类型不一致时会导致索引失效 。2.2 在索引字段上进行运算如下:
SELECT *FROM SomeTable WHERE col_1 * 1.1 > 100;
在索引字段col_1上进行运算会导致索引不生效,把运算的表达式放到查询条件的右侧,就能用到索引了,像下面这样写就OK了 。【优化 让SQL起飞】
WHERE col_1 > 100 / 1.1
如果无法避免在左侧进行运算,那么使用函数索引也是一种办法,但是不太推荐随意这么做 。「使用索引时,条件表达式的左侧应该是原始字段请牢记」,这一点是在优化索引时首要关注的地方 。2.3 使用否定形式下面这几种否定形式不能用到索引 。
- <>
- !=
- NOT
2.4 使用OR查询前后没有同时使用索引例如下表:
CREATE TABLE test_tb (id int(11) NOT NULL AUTO_INCREMENT,name varchar(55) NOT NULL PRIMARY KEY (id)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
使用OR条件进行查询SELECT * FROM test_tb WHERE id = 1 OR name = 'tom'
这个SQL的执行条件下,很明显id字段查询会走索引,但是对于OR后面name字段的查询是需要进行全表扫描的 。在这个场景下,优化器直接进行一遍全表扫描就完事了 。2.5 使用联合索引时,列的顺序错误使用联合索引需要满足最左匹配原则,即最左优先 。如果你建立一个(col_1, col_2, col_3)的联合索引,相当于建立了 (col_1)、(col_1,col_2)、(col_1,col_2,col_3) 三个索引 。如下例子:
-- 走了索引SELECT * FROM SomeTable WHERE col_1 = 10 AND col_2 = 100 AND col_3 = 500;-- 走了索引SELECT * FROM SomeTable WHERE col_1 = 10 AND col_2 = 100 ;-- 没走索引SELECT * FROM SomeTable WHERE col_1 = 10 AND col_3 = 500 ;-- 没走索引SELECT * FROM SomeTable WHERE col_2 = 100 AND col_3 = 500 ;-- 没走索引SELECT * FROM SomeTable WHERE col_2 = 100 AND col_1 = 10 ;
联合索引中的第一列(col_1)必须写在查询条件的开头,而且索引中列的顺序不能颠倒 。2.6 使用LIKE查询并不是用了like通配符,索引一定会失效,而是like查询是以%开头,才会导致索引失效 。
-- 没走索引SELECT*FROMSomeTableWHEREcol_1LIKE'%a';-- 没走索引SELECT*FROMSomeTableWHEREcol_1LIKE'%a%';-- 走了索引SELECT*FROMSomeTableWHEREcol_1LIKE'a%';
2.7 连接字段字符集编码不一致如果两张表进行连接,关联字段编码不一致会导致关联字段上的索引失效,这是博主在线上经历一次SQL慢查询后的得到的结果,举例如下,有如下两表,它们的name字段都建有索引,但是编码不一致,user表的name字段编码是utf8mb4,user_job表的name字段编码是utf8,CREATE TABLE `user` (`id` int NOT NULL AUTO_INCREMENT,`name` varchar(255) CHARACTERSET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,`age` int NOT NULL,PRIMARY KEY (`id`),KEY `idx_name` (`name`)) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;CREATE TABLE `user_job` (`id` int NOT NULL,`userId` int NOT NULL,`job` varchar(255) DEFAULT NULL,`name` varchar(255) DEFAULT NULL,PRIMARY KEY (`id`),KEY `idx_name` (`name`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
进行SQL查询如下:EXPLAINSELECT * from `user` u join user_job j on u.name = j.name
文章插图
由结果可知,user表的查询没有走索引 。想要user表也走索引,那就需要把user表name字段的编码改成utf8即可 。
三、减少中间表在SQL中,子查询的结果会被看成一张新表,这张新表与原始表一样,可以通过代码进行操作 。这种高度的相似性使得SQL编程具有非常强的灵活性,但是如果不加限制地大量使用中间表,会导致查询性能下降 。
推荐阅读
- 侧睡、喜皱眉、不卸妆……这些小习惯让你慢慢变丑
- |要怎样才能让自己变得更强大?
- 殷桃|比起殷桃的腰,她的这个地方更让广大网友羡慕!
- 大学生|“啃老”换了新模式,让父母心甘情愿被啃,甚至还觉得未来可期
- 专升本|央企招聘有新标准,二本生和专升本都不要,内部人的解释让人沉默
- |女星们的生图,让我意识到容貌焦虑的不必要
- 护肤|想要快速减肥?做好4件事,控制食欲、让胃口变小是关键!
- 招聘|学会拒绝,让你的工作更轻松
- 求职|真把自己当女猪脚了?女大学生实习看上富二代,花式讨好让人无语
- 厚黑学|厚黑学:掌握这三招,让你处事更得心应手