SQL_MySQL having 与 where 的区别 与 执行时机

本文详细解析了SQL中where子句与having子句的区别及使用场景,通过具体案例对比了两者在性能上的差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


参考文章地址 : http://blog.youkuaiyun.com/jdjh1024/article/details/76647866

聚合函数是比较where、having 的关键。 
开门见山。where、聚合函数、having 在from后面的执行顺序:

where>聚合函数(sum,min,max,avg,count)>having

列出group by来比较二者。()因where和having 在使用group by时用的最多) 
若须引入聚合函数来对group by 结果进行过滤 则只能用having。(此处不多说,自己想 是先执行聚合函数还是先过滤 然后比对我上面列出的执行顺序 一看便知)

样例:select sum(score) from student  where sex='man' group by name having sum(score)>210
   
  • 1

注意事项 : 
1、where 后不能跟聚合函数,因为where执行顺序大于(优先于)聚合函数。 
2、where 子句的作用是在对查询结果进行分组前,将不符合where条件的行去掉,即在分组之前过滤数据,条件中不能包含聚组函数,使用where条件显示特定的行。 
3、having 子句的作用是筛选满足条件的组,即在分组之后过滤数据,条件中经常包含聚组函数,使用having 条件显示特定的组,也可以使用多个分组标准进行分组。


实践出真知,让我们进行具体的实验!!!!!


测试场景说明 : 查询 某学生 的 平均成绩

测试创建表:
CREATE TABLE `test_having_where` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `type` varchar(255) DEFAULT NULL,
  `score` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `name_index` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=151868 DEFAULT CHARSET=utf8


插入15w条测试记录
package com.test.mysql;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Random;

/**
 * Created by szh on 2017/12/26.
 *
 * @author szh
 * @date 2017/12/26
 */
public class CreateDemoData {

    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        Boolean result = null;

        try {
            // 加载数据库驱动
            Class.forName("com.mysql.jdbc.Driver");

            // 通过驱动管理类获取数据库链接
            connection = DriverManager
                    .getConnection(
                            "jdbc:mysql://localhost:3306/td_dev?serverTimezone=Asia/Shanghai&characterEncoding=utf-8",
                            "root", "123456");
            // 定义sql语句 ?表示占位符
            String sql = "INSERT INTO test_having_where (`name`, type, score) VALUES (?, ?, ?)";
            preparedStatement = connection.prepareStatement(sql);

            String[] course = {"english", "chinese", "java", "css", "html"};

            Random random = new Random();


            for (int i = 0; i < 30000; i++) {

                StringBuffer tmpName = new StringBuffer();

                for (int m = 0; m < 8; m++) {
                    int key = random.nextInt() % 26;
                    char s = (char) ('a' + key);
                    tmpName.append(new Character(s));
                }


                preparedStatement.setString(1, tmpName.toString());


                for (int j = 0; j < course.length; j++) {

                    preparedStatement.setString(2, course[j]);
                    preparedStatement.setInt(3, Math.abs(random.nextInt() % 101));

                    // 向数据库发出sql执行查询,查询出结果集
                    result = preparedStatement.execute();
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 释放资源
//            if (resultSet != null) {
//                try {
//                    resultSet.close();
//                } catch (SQLException e) {
//                    // TODO Auto-generated catch block
//                    e.printStackTrace();
//                }
//            }
            if (preparedStatement != null) {
                try {
                    preparedStatement.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
}


构建完的测试数据



两种对比:
注意:
查询的时候一定要加入   sql_no_cache  在查询的时候禁用缓存
注意 这个例子比较极端,能完美的体现 二者之间的差异。

使用having
查询时间0.236s


使用where
查询时间 0.001s




再看下2条语句通过 explain 查看下执行的过程
having 


where


可以更加直观的看到扫描行数的问题!!!

好了,由此可以得出 where 的执行时机 确实在 having 之前, 并且 mysql 引擎并不会自动的帮我们进行优化 !!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值