MySql Optimization for仅从另一个表的列中选择具有最大值的行

时间:2016-11-25 16:35:34

标签: mysql

我正在制作电子商务脚本。

我有一张桌子" commerce_product"。

+--------------+---------+----------------------------+
| product_id   | title   | content                    |
+--------------+---------+----------------------------+
| 1            | ...     |  ...                       |
| 2            | ...     |  ...                       |
| 3            | ...     |  ...                       |
| 4            | ...     |  ...                       |
+--------------+---------+----------------------------+

我有一张桌子" commerce_product_price_index"。在此表中,我保存了每种产品的所有不同价格。 价格取决于customer_group,货币,国家,地理区域,客户和日期。

这是此表的一个示例。

+------+--------------+--------------------+--------------+-------------+-------------+----------+-------------+--------------+--------------+-------------+------------------+------------------+
| id   | product_id   | customer_group_id  | currency_id  | country_id  | geozone_id  | user_id  |  time_from  |  time_to     |   min_price  |  max_price  |  final_min_price |  final_max_price |
+------+--------------+--------------------+--------------+-------------+-------------+----------+-------------+--------------+--------------+-------------+------------------+------------------+
| 1    | 1            |  0                 | 0            | 0           | 0           | 0        | 1479942000  | 1480460400   | 500          | 500         | 300              | 300              |
| 2    | 1            |  1                 | 0            | 0           | 0           | 0        | 1479942000  | 1480460400   | 500          | 500         | 250              | 250              |
| 3    | 1            |  2                 | 0            | 0           | 0           | 0        | 1479942000  | 1480460400   | 500          | 500         | 200              | 200              |
| 4    | 1            |  3                 | 0            | 0           | 0           | 0        | 1479942000  | 1480460400   | 500          | 500         | 100              | 100              |
+------+--------------+--------------------+--------------+-------------+-------------+----------+-------------+--------------+--------------+-------------+------------------+------------------+

在这个例子中,我的产品有4种不同的价格。

首先,我选择计算每个价格的分数。

SELECT 
    IF (1480090146 >= `time_from` AND 1480090146 <= `time_to`, 1, 0) + 
    IF (`customer_group_id` = 3, 2, 0) + 
    IF (`geozone_id` = 2, 4, 0) + 
    IF (`country_id` = 73, 8, 0) + 
    IF (`currency_id` = 1, 16, 0)+ 
    IF (`user_id` = 2352, 32, 0) AS score,
    `cppi`.* 
    FROM 
        `commerce_product_price_index_2` AS `cppi` 
    WHERE 
        (geozone_id IN('2', 0)) 
        AND (country_id IN('73', 0)) 
        AND (currency_id IN('1', 0)) 
        AND (customer_group_id IN('3', 0)) 
        AND (user_id IN('2352', 0)) 
        AND (cppi.time_from <= 1480090146) 
        AND (cppi.time_to >= 1480090146) 
    ORDER BY `score` desc

我有2个结果,新的分数

+--------+------+--------------+--------------------+--------------+-------------+-------------+----------+-------------+--------------+--------------+-------------+------------------+------------------+
| score  | id   | product_id   | customer_group_id  | currency_id  | country_id  | geozone_id  | user_id  |  time_from  |  time_to     |   min_price  |  max_price  |  final_min_price |  final_max_price |
+--------+------+--------------+--------------------+--------------+-------------+-------------+----------+-------------+--------------+--------------+-------------+------------------+------------------+
| 3      | 1    | 1            |  0                 | 0            | 0           | 0           | 0        | 1479942000  | 1480460400   | 500          | 500         | 300              | 300              |
| 1      | 2    | 1            |  1                 | 0            | 0           | 0           | 0        | 1479942000  | 1480460400   | 500          | 500         | 250              | 250              |
+--------+------+--------------+--------------------+--------------+-------------+-------------+----------+-------------+--------------+--------------+-------------+------------------+------------------+

在这个结果中,我选择最高分来获得好价钱。

SELECT 
    `cppi2`.*, 
    MAX(score) 
FROM (
    SELECT 
        `cppi`.*, 
        IF (1480090146 >= `time_from` AND 1480090146 <= `time_to`, 1, 0) + 
        IF (`customer_group_id` = 3, 2, 0) + 
        IF (`geozone_id` = 2, 4, 0) + 
        IF (`country_id` = 73, 8, 0) + 
        IF (`currency_id` = 1, 16, 0)+ 
        IF (`user_id` = 2352, 32, 0) AS score 
        FROM 
            `commerce_product_price_index` AS `cppi` 
        WHERE 
            (geozone_id IN('2', 0)) 
            AND (country_id IN('73', 0)) 
            AND (currency_id IN('1', 0)) 
            AND (customer_group_id IN('3', 0)) 
            AND (user_id IN('2352', 0)) 
            AND (cppi.time_from <= 1480090146) 
            AND (cppi.time_to >= 1480090146) 
        ORDER BY `score` desc   

    ) AS `cppi2` 
GROUP BY `product_id`

在我选择产品表后,我就加入了这个请求。

我的问题是:这是制作它的好方法吗?

我的产品表有13000行。 我的价格指数表有50000行。

你有最好的解决方案吗?

1 个答案:

答案 0 :(得分:0)

看起来您可以从分数计算中删除time_fromtime_to部分,因为这是WHERE子句的一部分。

ORDER BY score - MAX(score)无需处理此事。

您应该考虑只选择所需的列而不是SELECT cppi.*

你的解决方案对我来说似乎很合理。其他解决方案包括计算代码中的分数(或者只是使用if / else / case语句优先选择某个价格索引来依次检查user_id,customer_group_id等),而不是使用mysql。

我试图提出一个解决方案,使用计算出的布尔标志来确定属性是否匹配,然后由它们排序,但我无法使用GROUP BY product_id。那里可能有一个解决方案,但我认为它不会更快。