簡體   English   中英

從兩個表中檢索數據的優化/最佳方法是什么?

[英]What is the optimized/best way to retrieve data from two tables?

我有兩張桌子。

post table

|post_id | post_title |
+--------+------------+
| 1      | Post 1     |
| 2      | Post 2     |
| 3      | Post 3     |

post_creator table

|post_id | creator |
+--------+---------+
| 1      | John    | 
| 1      | Smith   | 
| 1      | Mike    |
| 2      | Bob     |
| 3      | Peter   |
| 3      | Brad    |

當我加入這些表時,它看起來像這樣。

SELECT * 
FROM post p
JOIN post_creator c ON p.post_id = c.post_id


|post_id | post_title | post_id | creator|
+----------------------------------------+
| 1      | Post 1     | 1       | John   |
| 1      | Post 1     | 1       | Smith  |
| 1      | Post 1     | 1       | Mike   |
| 2      | Post 2     | 2       | Bob    |
| 3      | Post 3     | 3       | Peter  |
| 3      | Post 3     | 3       | Brad   |

我想和它的創造者一起抓住每一個帖子。 但是在這種情況下,由於創建者的原因,我的加入結果一次又一次地重復了相同的帖子

我所做的是首先從 post 表中獲取所有數據。 然后我循環該結果並在循環內獲取每個帖子的所有創建者。 但在這種情況下,它會一次又一次地查詢每個內容以獲取創建者。

$sql = "SELECT * FROM post";
$stmt = $conn->prepare($sql);
$stmt->execute();
$res = $stmt->fetchAll(PDO::FETCH_OBJ);

$dataObj = new stdClass;
$dataArr = [];

foreach($res as $post){
  $sql = "SELECT creator FROM post_creator WHERE post_id=$post->post_id";
  $stmt = $conn->prepare($sql);
  $stmt->execute();
  $creators = $stmt->fetchAll(PDO::FETCH_OBJ);
   
  $dataObj->post_id = $post->post_id
  $dataObj->post_title = $post->title
  $dataObj->creators = $creators;
  
  array_push($dataArr, $dataObj);
}

所以最后我的dataArr有這種結構。

[
  {
    post_id: 1, 
    post_title: Post 1, 
    creators:[John, Smith, Mike] 
  },
  
  {
    post_id: 2, 
    post_title: Post 2, 
    creators:[Bob] 
  },

  {
    post_id: 2, 
    post_title: Post 1, 
    creators:[Peter, Brad] 
  },
]

這就是我想要的。 現在我可以循環它並渲染到一個視圖。

有沒有優化/更好的方法來獲得這個結果,而無需一次又一次地循環和查詢?

我認為您需要使用group_concat對您的creators進行分組。

SELECT p.post_id, post_title, group_concat(creator) 
FROM post p
JOIN post_creator using(post_id) 
group by p.post_id

此外,這:

$sql = "SELECT creator FROM post_creator WHERE post_id=$post->post_id";
$stmt = $conn->prepare($sql);
$stmt->execute();

是對准備好的語句的不當使用。 它應該寫成:

$sql = "SELECT creator FROM post_creator WHERE post_id=?";
$stmt = $conn->prepare($sql);
$stmt->execute(array($post->post_id));

如果需要,但不是。 始終綁定值,從不直接放入 SQL。

我想說你可以走 3 條不同的道路,它們都有一些好處。

選項 1. 帶有 JOIN(和重疊行)的簡單 SELECT 查詢

這或多或少是您已經嘗試過的,您列出的第一個查詢; 這導致重復的行。

修改你的應用程序代碼來處理欺騙是相當簡單的,只需將創建者折疊到同一個數組/對象中。 開銷也幾乎為零。 從關系數據庫設計的角度來看,這種方法仍然是最佳實踐。

   SELECT p.post_id
        , p.post_title
        , c.creator
     FROM post         p
LEFT JOIN post_creator c 
       ON p.post_id = c.post_id
 ORDER BY p.post_id ASC

.

/* $rows = ...query...; */
$posts = [];
foreach ($rows as $row) {
    if (!isset($posts[( $row['post_id'] )])) {
        // this is a new post_id
        $post                       = [];
        $post['id']                 = $row['post_id'];
        $post['creators']           = [];
        $post['creators'][]         = $row['creator'];
        $posts[( $row['post_id'] )] = $post;
    } else {
        // this is just an additional creator
        $posts[( $row['post_id'] )]['creators'][] = $row['creator'];
    }
}

選項 2. 多值列(數組或 json)

對於非純粹主義者來說,更實用的解決方案是讓您的查詢生成包含多個值的 output 列。 這通常意味着 JSON 或 ARRAY 列。 確切的細節取決於您選擇的數據庫系統。

無論哪種情況,您都可以將其與 SQL GROUP BY功能結合使用。 假設您使用 MySQL 並且更喜歡 JSON 類型; 然后,您將使用以下查詢 go :

    SELECT p.post_id
         , p.post_title
         , JSON_ARRAYAGG(c.creator) AS creators
      FROM post         p
 LEFT JOIN post_creator c 
        ON p.post_id = c.post_id
  GROUP BY p.post_id
  ORDER BY p.post_id ASC

這樣,每個帖子您只會收到一條記錄,並且您將獲得諸如['Mike', 'Paul', 'Susan']類的值, json_decode()可以將其轉換為正確的 PHP 數組。

選項 3. 成熟的文件

另一種基於選項 #2 的替代方案是 go 完全與 JSON,並完全放棄關系記錄集。

大多數現代 DBMS 具有大量 JSON 功能和您自己列為dataArr的格式,可以由數據庫完全生成以響應單個SELECT查詢。

這樣,查詢將始終只產生 1 行 1 列,其中包含結合所有這些帖子的整個dataArr (再次,可以將其轉換為原生 PHP 數組或 object 樹與json_decode ,就像以前一樣)。

雖然這種方法的結果可能非常簡潔(取決於您的應用程序的編寫方式),但有些人可能想知道為什么您使用的是 RDBMS 而不是 MongoDB 之類的東西。


總的來說,我會推薦選項 1。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM