帮助使用16个子查询优化查询

时间:2010-05-27 14:10:19

标签: mysql optimization

我在每种类型的所有适当的ID字段上都有索引/原色。我想知道如何让这个更有效率。加载只有15,000行的页面需要一段时间,而且很快就会增长到500k。

$whereSql变量只有一些主ebay_archive_listing表的参数。

注意:这都是在一个查询中完成的,因为我对每个子查询值都有ASC / DESC排序。

注意:我已将部分子查询转换为INNER JOIN

更新

当我更改所有子查询值以使用如下所示的相同子查询时,我得到以下SQL错误: Unknown column 'product_master.product_id' in 'on clause

我只能假设这是指提取所有AVG,MIN和MAX的子查询,因为它是我唯一改变的东西。虽然我不确定为什么它现在抛出这个错误而不是它全部分裂成不同的值。

SELECT
                product_master.product_id,
                (
                    SELECT
                        COUNT(listing_id)
                    FROM ebay_archive_product_listing_assoc '.$listingCountJoin.'
                    WHERE ebay_archive_product_listing_assoc.product_id = product_master.product_id) as listing_count,
                sku,
                type_id,
                (
                    SELECT
                        AVG(ebay_archive_listing.current_price) AS average_bid_price,
                        AVG(ebay_archive_listing.buy_it_now_price) AS average_buyout_price,
                        MIN(ebay_archive_listing.current_price) AS lowest_bid_price,
                        MAX(ebay_archive_listing.current_price) AS highest_bid_price,
                        MIN(ebay_archive_listing.buy_it_now_price) AS lowest_buyout_price,
                        MAX(ebay_archive_listing.buy_it_now_price) AS highest_buyout_price
                    FROM ebay_archive_listing
                    INNER JOIN ebay_archive_product_listing_assoc ON (
                        ebay_archive_product_listing_assoc.listing_id = ebay_archive_listing.id AND
                        ebay_archive_product_listing_assoc.product_id = product_master.product_id
                    )
                    WHERE '.$whereSql.' AND
                    ebay_archive_listing.current_price > 0
                ),
                round(((
                        SELECT
                            COUNT(ebay_archive_listing.id)
                        FROM ebay_archive_listing
                    INNER JOIN ebay_archive_product_listing_assoc ON (
                        ebay_archive_product_listing_assoc.listing_id = ebay_archive_listing.id AND
                        ebay_archive_product_listing_assoc.product_id = product_master.product_id
                    )
                    WHERE '.$whereSql.' AND
                        ebay_archive_listing.status_id = 2
                    ) / (
                    SELECT
                        COUNT(listing_id)
                    FROM ebay_archive_product_listing_assoc '.$listingCountJoin.'
                    WHERE ebay_archive_product_listing_assoc.product_id = product_master.product_id ) * 100), 1) as sold_percent
            FROM product_master
            '.$joinSql.'
            WHERE product_master.product_id IN (
                SELECT
                    product_id
                FROM ebay_archive_product_listing_assoc
                INNER JOIN ebay_archive_listing ON (
                    ebay_archive_listing.id = ebay_archive_product_listing_assoc.listing_id AND 
                    '.$whereSql.'
                )
            )

=======================以下原文====================== =====================

SELECT
                    product_master.product_id,
                    (
                        SELECT
                            COUNT(listing_id)
                        FROM ebay_archive_product_listing_assoc '.$listingCountJoin.'
                        WHERE ebay_archive_product_listing_assoc.product_id = product_master.product_id) as listing_count,
                    sku,
                    type_id,
                    (
                        SELECT
                            AVG(ebay_archive_listing.current_price)
                        FROM ebay_archive_listing
                        INNER JOIN ebay_archive_product_listing_assoc ON (
                            ebay_archive_product_listing_assoc.listing_id = ebay_archive_listing.id AND
                            ebay_archive_product_listing_assoc.product_id = product_master.product_id
                        )
                        WHERE '.$whereSql.' AND
                        ebay_archive_listing.current_price > 0
                    ) as average_bid_price,
                    (
                        SELECT
                            AVG(ebay_archive_listing.buy_it_now_price)
                        FROM ebay_archive_listing
                        INNER JOIN ebay_archive_product_listing_assoc ON (
                            ebay_archive_product_listing_assoc.listing_id = ebay_archive_listing.id AND
                            ebay_archive_product_listing_assoc.product_id = product_master.product_id
                        )
                        WHERE '.$whereSql.' AND
                        ebay_archive_listing.buy_it_now_price > 0
                    ) as average_buyout_price,
                    (
                        SELECT
                            MIN(ebay_archive_listing.current_price)
                        FROM ebay_archive_listing
                        INNER JOIN ebay_archive_product_listing_assoc ON (
                            ebay_archive_product_listing_assoc.listing_id = ebay_archive_listing.id AND
                            ebay_archive_product_listing_assoc.product_id = product_master.product_id
                        )
                        WHERE '.$whereSql.' AND
                        ebay_archive_listing.current_price > 0
                    ) as lowest_bid_price,
                    (
                        SELECT
                            MAX(ebay_archive_listing.current_price)
                        FROM ebay_archive_listing
                        INNER JOIN ebay_archive_product_listing_assoc ON (
                            ebay_archive_product_listing_assoc.listing_id = ebay_archive_listing.id AND
                            ebay_archive_product_listing_assoc.product_id = product_master.product_id
                        )
                        WHERE '.$whereSql.' AND
                        ebay_archive_listing.current_price > 0
                    ) as highest_bid_price,
                    (
                        SELECT
                            MIN(ebay_archive_listing.buy_it_now_price)
                        FROM ebay_archive_listing
                        INNER JOIN ebay_archive_product_listing_assoc ON (
                            ebay_archive_product_listing_assoc.listing_id = ebay_archive_listing.id AND
                            ebay_archive_product_listing_assoc.product_id = product_master.product_id
                        )
                        WHERE '.$whereSql.' AND
                        ebay_archive_listing.current_price > 0
                    ) as lowest_buyout_price,
                    (
                        SELECT
                            MAX(ebay_archive_listing.buy_it_now_price)
                        FROM ebay_archive_listing
                        INNER JOIN ebay_archive_product_listing_assoc ON (
                            ebay_archive_product_listing_assoc.listing_id = ebay_archive_listing.id AND
                            ebay_archive_product_listing_assoc.product_id = product_master.product_id
                        )
                        WHERE '.$whereSql.' AND
                        ebay_archive_listing.current_price > 0
                    ) as highest_buyout_price,
                    round(((
                            SELECT
                                COUNT(ebay_archive_listing.id)
                            FROM ebay_archive_listing
                        INNER JOIN ebay_archive_product_listing_assoc ON (
                            ebay_archive_product_listing_assoc.listing_id = ebay_archive_listing.id AND
                            ebay_archive_product_listing_assoc.product_id = product_master.product_id
                        )
                        WHERE '.$whereSql.' AND
                            ebay_archive_listing.status_id = 2
                        ) / (
                        SELECT
                            COUNT(listing_id)
                        FROM ebay_archive_product_listing_assoc '.$listingCountJoin.'
                        WHERE ebay_archive_product_listing_assoc.product_id = product_master.product_id ) * 100), 1) as sold_percent
                FROM product_master
                '.$joinSql.'
                WHERE product_master.product_id IN (
                    SELECT
                        product_id
                    FROM ebay_archive_product_listing_assoc
                    INNER JOIN ebay_archive_listing ON (
                        ebay_archive_listing.id = ebay_archive_product_listing_assoc.listing_id AND 
                        '.$whereSql.'
                    )
                )

4 个答案:

答案 0 :(得分:3)

虽然我不确定你的whereSql可能带来什么,但使用简单连接来做这类事情似乎要容易得多(也更快)。在你真的需要之前不要诉诸子查询。

诀窍是使用CASE条件排除您不想要的0价格列以返回NULL(聚合函数将忽略),而不是尝试将该条件放入子查询WHERE子句:

SELECT
    p.product_id, p.sku, p.type_id,
    COUNT(l.listing_id) AS listing_count,
    AVG(CASE WHEN l.current_price>0 THEN l.current_price ELSE NULL END) AS average_bid_price,
    MIN(CASE WHEN l.current_price>0 THEN l.current_price ELSE NULL END) AS lowest_bid_price,
    MAX(CASE WHEN l.current_price>0 THEN l.current_price ELSE NULL END) AS highest_bid_price,
    AVG(CASE WHEN l.buy_it_now_price>0 THEN l.buy_it_now_price ELSE NULL END) AS average_buyout_price,
    MIN(CASE WHEN l.buy_it_now_price>0 THEN l.buy_it_now_price ELSE NULL END) AS lowest_buyout_price,
    MAX(CASE WHEN l.buy_it_now_price>0 THEN l.buy_it_now_price ELSE NULL END) AS highest_buyout_price,
    AVG(CASE WHEN l.status_id=2 THEN 100 ELSE 0 END) AS sold_percent
FROM product_master AS p
    JOIN ebay_archive_product_listing_assoc AS pl ON pl.product_id=p.product_id
    JOIN ebay_archive_listing AS l ON l.listing_id=pl.listing_id
GROUP BY p.product_id
WHERE '.$whereSql.'

答案 1 :(得分:1)

我理解您需要更快的查询。但你也应该读到这个:

http://en.wikipedia.org/wiki/SQL_injection

至于你的查询,你至少应该:

  • 尽可能避免相关子查询(取决于数据量,查询选择性,索引和DBMS优化器)

  • 在同一子查询中检索min(),max()和avg()

  • 提供了一个完整的示例,因为没有人知道$ whereSql,$ listingCountJoin和$ joinSql中的内容。

关于这个主题的好书,我建议Refactoring SQL Applications

答案 2 :(得分:1)

1)摆脱重复的查询。 通过从...中选择MIN(...),MAX(...),AVG(...)两个类别。

答案 3 :(得分:0)

有点像这样的东西更好

SELECT
                product_master.product_id,
                (
                    SELECT
                        COUNT(listing_id)
                    FROM ebay_archive_product_listing_assoc '.$listingCountJoin.'
                    WHERE ebay_archive_product_listing_assoc.product_id = product_master.product_id) as listing_count,
                sku,
                type_id,
                average_bid_price,     
                average_buyout_price,     
                lowest_bid_price,     
                highest_bid_price,     
                lowest_buyout_price,     
                highest_buyout_price,     
                round(((
                        SELECT
                            COUNT(ebay_archive_listing.id)
                        FROM ebay_archive_listing
                    INNER JOIN ebay_archive_product_listing_assoc ON (
                        ebay_archive_product_listing_assoc.listing_id = ebay_archive_listing.id AND
                        ebay_archive_product_listing_assoc.product_id = product_master.product_id
                    )
                    WHERE '.$whereSql.' AND
                        ebay_archive_listing.status_id = 2
                    ) / (
                    SELECT
                        COUNT(listing_id)
                    FROM ebay_archive_product_listing_assoc '.$listingCountJoin.'
                    WHERE ebay_archive_product_listing_assoc.product_id = product_master.product_id ) * 100), 1) as sold_percent
            FROM product_master LEFT OUTER JOIN
                (
                    SELECT ebay_archive_product_listing_assoc.product_id ,
                        AVG(ebay_archive_listing.current_price) average_bid_price,
                        AVG(ebay_archive_listing.buy_it_now_price) average_buyout_price,
                        MIN(ebay_archive_listing.current_price) lowest_bid_price,
                        MAX(ebay_archive_listing.current_price) highest_bid_price,
                        MIN(ebay_archive_listing.buy_it_now_price) lowest_buyout_price,
                        MAX(ebay_archive_listing.buy_it_now_price) highest_buyout_price
                    FROM ebay_archive_listing
                    INNER JOIN ebay_archive_product_listing_assoc ON (
                        ebay_archive_product_listing_assoc.listing_id = ebay_archive_listing.id 
                    )
                    WHERE '.$whereSql.' AND
                    ebay_archive_listing.current_price > 0
                    GROUP BY ebay_archive_product_listing_assoc.product_id
                ) eal ON eal.product_id = product_master.product_id
            '.$joinSql.'
            WHERE product_master.product_id IN (
                SELECT
                    product_id
                FROM ebay_archive_product_listing_assoc
                INNER JOIN ebay_archive_listing ON (
                    ebay_archive_listing.id = ebay_archive_product_listing_assoc.listing_id AND
                    '.$whereSql.'
                )
            )

但是还可以做更多的事情,whereSql和joinSql的值是什么?