Mysql

在多個表上使用 LEFT JOIN 的困惑

  • December 7, 2021

我可能在這裡誤解了一些基本的東西,但我很難找到在我的研究中解釋的這個問題。

假設我們有一個使用者表和其他與使用者相關的表,我們稱它們為:

  • 訂單(包含使用者 ID)
  • 評論(包含使用者 ID)
  • 疫苗接種(包含使用者 ID)

每個使用者可以有許多訂單、評論或疫苗接種。

現在讓我們說,對於我正在編寫的任何程式碼,我都希望獲得所有使用者、他們的所有訂單、評論和疫苗接種。

我應該編寫一個將所有內容連接在一起的查詢,還是三個單獨的查詢?

IE應該是這樣的:

SELECT  *
   FROM  users
   LEFT JOIN  orders  ON orders.userId = users.id
   LEFT JOIN  reviews  ON reviews.userId = users.id
   LEFT JOIN  vaccinations  ON vaccinations.userId = users.id 

或三個完全獨立的查詢,例如:

  1. SELECT * FROM users LEFT JOIN orders ON orders.userId = users.id
  2. SELECT * FROM users LEFT JOIN reviews ON reviews.userId = users.id
  3. SELECT * FROM users LEFT JOIN 疫苗接種 on 疫苗接種.userId = users.id

一些背景

我認為讓我感到困惑的是,我花在查詢 SQL 上的大部分時間都在使用節點 ORM Sequelize。它允許我使用從表面上看是有意義的單個查詢來愉快地查詢數據庫。像這樣的東西:

return models.users.findAll({
include: [{
   model: models.orders
   required: false
},
{ 
   model: models.reviews,
   required: false
}, 
{
   model: models.vaccinations, 
   required: false
}],

});

在程式碼中,它以一種非常好的有序方式將結果返回給我,這很有意義。然而,當我查看 MySQL 的“慢查詢”日誌時,我意識到其中一些連接在每個查詢中返回了數十萬個結果。我猜這是由於其中一個表中的一個額外行意味著查詢然後返回更多結果。

只是重複這個問題以結束我應該編寫一個將所有內容連接在一起的查詢,還是三個單獨的查詢?

非常感謝你的幫助。

對此沒有一般性的答案。基本上:如果連接使數字爆炸,那麼以不同的方式執行多個查詢可能是有意義的,但這基本上是一種權衡,您必鬚根據具體情況進行評估。

在您的範例中,我通常會拒絕查詢-幾乎沒有任何場景需要所有擴展的所有使用者。這裡的問題不是從擴展開始,而是從沒有過濾開始。甚至沒有分頁。這就是您的問題(在那個束中)開始的地方。

查詢 1:這會返回很多行,因為所有 4 個查詢之間沒有關係。它還為反 vaxxers 返回 NULL:

SELECT  *
   FROM  users
   LEFT JOIN  orders  ON orders.userId = users.id
   LEFT JOIN  reviews  ON reviews.userId = users.id
   LEFT JOIN  vaccinations  ON vaccinations.userId = users.id 

查詢 2:這會將它們從列表中刪除。

SELECT  *
   FROM  users
   JOIN  orders  ON orders.userId = users.id
   JOIN  reviews  ON reviews.userId = users.id
   JOIN  vaccinations  ON vaccinations.userId = users.id 

查詢 3:這僅給每個使用者一行,並包括一些計數:

SELECT  users.*,
       ( SELECT COUNT(*) FROM orders  ON orders.userId = users.id ) AS order_ct,
       ( SELECT COUNT(*) FROM reviews  ON reviews.userId = users.id ) AS review_ct
       ( SELECT COUNT(*) FROM vaccinations  ON vaccinations.userId = users.id ) AS vax_ct
   FROM  users

查詢 4:這給出了 3 組資訊。它沒有列出未接種疫苗的疫苗資訊。

SELECT  *  FROM  users
   JOIN  orders  ON orders.userId = users.id;
SELECT  *  FROM  users
   JOIN  reviews  ON reviews.userId = users.id;
SELECT  *  FROM  users
   JOIN  vaccinations  ON vaccinations.userId = users.id ;

查詢 5:這給出了 3 組資訊,但包括反 vaxxers 的 NULL:

SELECT  *  FROM  users
   LEFT JOIN  orders  ON orders.userId = users.id;
SELECT  *  FROM  users
   LEFT JOIN  reviews  ON reviews.userId = users.id;
SELECT  *  FROM  users
   LEFT JOIN  vaccinations  ON vaccinations.userId = users.id ;

目前還不清楚你想要什麼。查詢 4 或 5 可能是您需要的。

(我對框架的了解不夠,所以我無法進一步混淆它的表述。)

引用自:https://dba.stackexchange.com/questions/303544