【问题标题】:Temporary Table and Left Joins not showing results as expected临时表和左连接未按预期显示结果
【发布时间】:2012-03-01 10:23:38
【问题描述】:

我真的希望有人可以帮助我解决这个问题。我有许多产品属性类型,用户可以从中选择以细化屏幕上返回给他们的产品。我想要做的是,对于每种产品属性类型,我想列出与所选类别或搜索词相关的所有属性,然后一旦他们做出选择,我仍然想显示每个属性与类别或搜索词相关的链接,但仅在该特定属性的产品计数大于 1 时才显示可点击链接,对于产品计数为零的产品,我想列出它们,但使其不可点击。我正在尝试实现的示例可以在 ASOS 网站的左侧菜单中找到 http://www.asos.com/Women/Dresses/Cat/pgecategory.aspx?cid=8799#state=Rf961%3D3340%2C3341%40Rf-200%3D20&parentID=Rf-300&pge=0&pgeSize=20&sort=-1

最初我尝试使用仅连接来实现这一点,但我无法成功地做到这一点。所以我决定为每个属性类型创建一个临时表,其中包含与主查询相关的所有属性的列表,然后创建一个带有左连接的细化查询。这是我的代码:

CREATE TEMPORARY TABLE temp_table 
    SELECT su_types.id, type AS item FROM su_types 
    INNER JOIN su_typerefs ON su_types.id=su_typerefs.id 
    INNER JOIN su_pref ON su_typerefs.mykey = su_pref.mykey 
WHERE wp_category_id =40 GROUP BY su_typerefs.id

$sudb->query($query);

if ($sudb->affected_rows > 0) {     

SELECT temp_table.id,item,COUNT(su_typerefs.mykey) AS product_count FROM temp_table 
    LEFT JOIN su_typerefs ON temp_table.id=su_typerefs.id 
    LEFT JOIN su_pref ON su_typerefs.mykey = su_pref.mykey 
    LEFT JOIN su_stylerefs ON su_pref.mykey = su_stylerefs.mykey 
    LEFT JOIN su_productrefs ON su_pref.mykey = su_productrefs.mykey
WHERE wp_category_id =40 AND su_stylerefs.id in (91) AND su_productrefs.id in (54) AND su_typerefs.id in (159) GROUP BY su_typerefs.id

if ($itemresults = $sudb->query($query)) {

    while($itemresult = $itemresults->fetch_array(MYSQLI_ASSOC)) {
    $id=$itemresult['id'];
    $item=$itemresult['item'];
    $product_count=$itemresult['product_count'];


        build_link($list_type, $item, $product_count, $id);
    }
}

在上面的示例中,第一个查询选择了与特定类别相关的所有产品类型,例如连衣裙。第二个查询基于用户对类别所做的细化,在本例中是产品、产品类型和样式。用户还可以按颜色、合身度、面料和设计细化他们的搜索。

这有几个问题:

1) 第二个查询返回的结果数与第一个查询的结果不匹配。以上面为例,我希望列出与所选类别相关的所有产品,然后使用第二个查询返回每个产品的产品计数,如上所述。所以如果临时表返回,裤子,牛仔裤和裙子。我希望根据第二个查询中应用的条件将这三个项目显示在屏幕上,但是如果第二个查询中没有匹配裙子,我的结果可能只显示裤子和牛仔裤。我认为使用左连接意味着将显示临时表的所有结果。

2)我也想知道我这样做是否是最有效的方式。我一共有8个属性组,因此需要做以上8次。如果用户选择使用所有 8 个属性组来优化结果,那么除了临时表连接之外,每种类型总共会有 9 个连接。执行需要一段时间,有没有更好的方法来执行此操作?表中大约有 1/2 百万种产品,一旦我的网站上线,这可能是这个数字的 5 倍。

我真的希望我所写的一切都有意义,如果有人可以提供帮助,我将非常感谢 stackoverflow 社区在这方面的帮助。我为这篇文章道歉;)。提前致谢

【问题讨论】:

    标签: php mysql left-join temp-tables


    【解决方案1】:

    回答您的第一个问题;是的,LEFT JOIN 确实会保留初始表中的所有数据。然而,这不是问题。

    您丢失空类别的原因很可能(我这么说是因为我不完全了解您的数据库结构),因为 where 条件会根据连接表中的数据过滤掉所有结果。 如果某个类别的所有项目都被过滤掉(可能包括 NULL 连接值),您将不再从该查询中获取该类别。此外,GROUP BY 是在连接列上完成的,这也可能有效地消除您的其他类别。

    至于第二个问题,您已经说过需要很长时间;所以如果你想让事情快速工作,这可能不是你要走的路;)(好的,显而易见的答案,低悬的果实等)。您可能想要做的是首先从可过滤类别中获取一组键,然后使用该数据来选择项目。

    这可以防止您必须将整个产品表连接到一个临时表中(至少,我认为您正在这样做),这对于给定数量的条目当然会花费很长时间。从给定属性中选择匹配 ID 的列表还可以让您提前使用索引(更多),而临时表可能没有这些索引。这是否可行和可行主要取决于您的架构的结构;但我希望它能引导你走向你想去的方向:)

    【讨论】:

    • 您好 Yhn,感谢您的回复,临时表并未从表中检索所有属性,而是仅检索与所选类别相关的属性。我之前将第二个查询构造为一个循环,遍历我想要计数的每个键。这非常有效,但它花费了相同的时间,如果不是更多的话。目前加载整个页面大约需要 30 秒,这是不可接受的吗?
    • 30 秒只是一些计数统计听起来确实应该能够更好地工作......您可以尝试检查两个查询的时间(只是为了确认两者中的哪一个实际上导致了问题) .之后,您可以尝试使用 EXPLAIN [query] 的输出来查看索引是否正确用于连接和位置。也许没有临时表它可以更快地工作(因为它可能没有索引;而实际的表有)。
    • 我试图对临时表查询进行解释,但我做不到。但是对 sedond 查询的解释看起来不错。如果我不使用临时表,那么我必须创建循环通过第一个查询的第二个查询,而不是将第二个查询加入临时表并一次返回所有结果
    • 我在加入大表方面的经验(即使限制了位置),这对于 MySQL 来说太长了。你可能会遇到同样的问题。我使用所说的大表(在我的例子中是 550 万条记录)的方式是首先收集选择标准(以该大表中存在的 id 的形式),然后使用它从大表中选择有用的行,使用指数。这也可能为您加快速度。至于没有出现的类别;将您的 GROUP BY 更改为临时表的“id”字段可能会修复它(因为该字段始终与联接一起存在)。
    猜你喜欢
    • 1970-01-01
    • 2015-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多