2011-12-20 30 views
3

我遇到一篇關於連接分解的文章。PHP內連接分解

場景#1(不好):

Select * from tag 
Join tag_post ON tag_post.tag_id=tag.id 
Join post ON tag_post.post_id=post.id 
Where tag.tag='mysql' 

場景#2(好):

Select * from tag where tag='mysql' 

Select * from tag_post Where tag_id=1234 

Select * from post where post.id in (123,456,9098,545) 

有人建議要堅持場景#2的原因有很多專緩存。 問題是如何加入我們的應用程序。你可以給我們一個PHP 個別檢索後的例子嗎? (我已閱讀MyISAM Performance: Join Decomposition? 但它沒有幫助)

回答

2

你可以使用SQL子查詢(如果我理解你的問題)。使用PHP會很奇怪,而SQL具有所有功能。

SELECT * 
FROM `post` 
WHERE `id` IN (
    SELECT `post_id` 
    FROM `tag_post` 
    WHERE `tag_id` = (
     SELECT `tag_id` 
     FROM `tag` 
     WHERE `tag` = 'mysql' 
    ) 
) 

我不知道你的數據庫結構是怎麼樣的,但這應該讓你開始。這幾乎是SQL開始。查詢中的查詢。您可以使用子選擇的結果選擇數據。

請在複製此SQL並告訴我它不起作用之前,請驗證所有表名和列名。

在任何人開始關注速度,緩存和效率之前:我認爲這是相當有效的。而不是選擇所有數據並使用PHP循環訪問,您可以使用原生SQL選擇較小的位,因爲這是使用它的必要條件。

同樣,我非常不願意使用PHP來獲取特定的數據。 SQL是你所需要的。


編輯:這裏是你的腳本

假設你有一個包含所有數據的一些多維數組:

// dummy results 

// table tag 
$tags = array(
    // first record 
    array(
     'id' => 0, 
     'tag' => 'mysql' 
    ), 
    // second record 
    array(
     'id' => 1, 
     'tag' => 'php' 
    ) 
    // etc 
); 

// table tag_post 
$tag_posts = array(
    // first record 
    array(
     'id'  => 0, 
     'post_id' => 0, // post #1 
     'tag_id' => 0 // has tag mysql 
    ), 
    // second record 
    array(
     'id'  => 1, 
     'post_id' => 1, // post #2 
     'tag_id' => 0 // has tag mysql 
    ), 
    // second record 
    array(
     'id'  => 2, 
     'post_id' => 2, // post #3 
     'tag_id' => 1 // has tag mysql 
    ) 
    // etc 
); 

// table post 
$posts = array(
    // first record 
    array(
     'id'  => 0, 
     'content' => 'content post #1' 
    ), 
    // second record 
    array(
     'id'  => 1, 
     'content' => 'content post #2' 
    ), 
    // third record 
    array(
     'id'  => 2, 
     'content' => 'content post #3' 
    ) 
    // etc 
); 

// searching for tag 
$tag = 'mysql'; 
$tagid = -1; 
$postids = array(); 
$results = array(); 

// first get the id of this tag 
foreach($tags as $key => $value) { 
    if($value['tag'] === $tag) { 
     // set the id of the tag 
     $tagid = $value['id']; 

     // theres only one possible id, so we break the loop 
     break; 
    } 
} 

// get post ids using the tag id 
if($tagid > -1) { // verify if a tag id was found 
    foreach($tag_posts as $key => $value) { 
     if($value['tag_id'] === $tagid) { 
      // add post id to post ids 
      $postids[] = $value['post_id']; 
     } 
    } 
} 

// finally get post content 
if(count($postids) > 0) { //verify if some posts were found 
    foreach($posts as $key => $value) { 
     // check if the id of the post can be found in the posts ids we have found 
     if(in_array($value['id'], $postids)) { 
      // add all data of the post to result 
      $results[] = $value; 
     } 
    } 
} 

如果你看一下上面的腳本的長度,這是究竟爲什麼我會堅持SQL。

現在,我記得,你想要join使用PHP,而不是在SQL中。這不是一個連接,而是使用一些數組獲得結果。我知道,但加入只會浪費時間,並且效率低於僅僅保留所有結果。


編輯:21-12-12如下面

我已經做了一些基準測試和評價結果的結果是相當驚人:

DATABASE RECORDS: 
tags:   10 
posts:   1000 
tag_posts:  1000 (every post has 1 random tag) 

Selecting all posts with a specific tag resulted in 82 records. 

SUBSELECT RESULTS: 
run time:      0.772885084152 
bytes downloaded from database: 3417 

PHP RESULTS: 
run time:      0.086599111557 
bytes downloaded from database: 48644 



Please note that the benchmark had both the application as the database on the 
same host. If you use different hosts for the application and the database layer, 
the PHP result could end up taking longer because naturally sending data between 
two hosts will take much more time then when they're on the same host. 

即使再選擇返回的數據少得多,請求的持續時間接近10倍...

我從來不期望這些結果,所以我相信,我一定會利用這一信息時,我知道,但是我仍然會使用SQL較小的操作嘿嘿性能是重要的......

+0

TNX花花公子,我知道關於子查詢,但文章的重點是在應用程序內部加入不同的選擇,而不是將它們與MySQL結合起來! – ALH 2011-12-20 10:25:41

+0

當SQL提供您需要的所有工具時,您爲什麼要在應用程序中執行此操作? – 2011-12-20 10:30:19

+0

**高性能MySQL **書中說:您可以通過運行多個單表查詢而不是多可連接來分解連接,然後在應用程序中執行連接! – ALH 2011-12-20 10:37:28