Rails 3 中生 MySQL subquery 的秘技
http://blog.rocodev.com/posts/13-mysql-subquery-in-rails-3 有時候設計 Rails Application 時,某些 JOIN 的語法並不是那麼好寫。(不管是手刻,或者是透過 ORM 下出來。) 所以在 Application 層( PHP or Rails) 下兩次 SELECT 或者是用 subquery 往往
http://blog.rocodev.com/posts/13-mysql-subquery-in-rails-3
有時候設計 Rails Application 時,某些 JOIN 的語法並不是那麼好寫。(不管是手刻,或者是透過 ORM 下出來。)
所以在 Application 層( PHP or Rails) 下兩次 SELECT 或者是用 subquery 往往會變成直覺下的取代方案。
舉個例子,有個功能叫做:我上架的書有被人 facvorite 的總數量。
一般開發者在不用 JOIN 的情況下,會寫出這樣的 code
book_ids = Book.where(:user_id => user.id) favorite_count = Favorite.where(:book_id => book_ids).select("book_id").map(&:book_id).uniq.size
因為你無法知道 book_ids 怎麼拉出來丟 query,只好拉到 Application 層再塞回去用 IN 撈。數量小這樣的作法是還 okay….但…萬一 book_ids 多達萬,顯然這招就效了。除了慢之外,還製造一堆無用物件浪費記憶體空間…
而 Rails 3 背後強大的 Arel,其實提供了自動算出 subquery 的語法:
其實上面那一段可以改為這樣寫
favorite_count = Favorite.where(:book_id => Book.where(:user_id => user.id)).select("distinct book_id").count
是的,在查詢語句裡面再下條件就會自動變成 subquery 了....
Favorite.where(:book_id => Book.where(:user_id => user.id))
http://*.com/questions/5483407/subqueries-in-activerecord
幾個原則
- 不是 JOIN 就是慢
- 兩個 SELECT 不一定比 JOIN 快。(在以上 book_id 數量很大的 case 中)
- 兩個 SELECT 有時候會比 JOIN 快。(在以上 book_id 數量很小的 case 中)
- 有時候應該用 SUBQUERY 取代兩個 SELECT
- SUBQUERY 不是萬靈丹,因為大多時候 JOIN 蠻多時候比 SUBQUERY 有效率,但 SUBQUERY 好寫蠻多的,可偷吃步…
- SUBQUERY 適可而止,太多層 SUBQUERY 效能掉很兇(兩層其實就慢了...)。
原文地址:Rails 3 中生 MySQL subquery 的秘技, 感谢原作者分享。