Votre requête est presque correcte et c'est la bonne façon de le faire (et la plus efficace)
SELECT books.*, count(orders.book_id) as number_of_orders
from books
left join orders
on (books.book_id = orders.book_id)
group by
books.book_id
COUNT(*)
pourrait inclure des valeurs NULL dans le décompte car il compte toutes les lignes, tandis que COUNT(orders.book_id)
ne le fait pas car il ignore les valeurs NULL dans le champ donné.