Есть исчерпывающий ответ на этот вопрос в документации к Postgresql. Вот его перевод с сайта Postgres Pro:
Основное отличие WHERE от HAVING заключается в том, что WHERE сначала выбирает строки, а затем группирует их и вычисляет агрегатные функции (таким образом, она отбирает строки для вычисления агрегатов), тогда как HAVING отбирает строки групп после группировки и вычисления агрегатных функций. Как следствие, предложение WHERE не должно содержать агрегатных функций; не имеет смысла использовать агрегатные функции для определения строк для вычисления агрегатных функций. Предложение HAVING, напротив, всегда содержит агрегатные функции. (Строго говоря, вы можете написать предложение HAVING, не используя агрегаты, но это редко бывает полезно. То же самое условие может работать более эффективно на стадии WHERE.)
Но вас также может заинтересовать:
- Как работает реляционная БД на Хабре
- How does a relational database work
- How does a relational database execute SQL statements and prepared statements
- How Database Internally Works
- Курс по БД от Ильи Тетерина или курс от Вадима Цесько
- Let's Build a Simple Database
- Database internals