2011-12-20 68 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