如何在多个自联接上指定排序顺序

时间:2015-04-25 15:11:28

标签: mysql sql

我有像

这样的属性表
CREATE TABLE attributes (
    attribute_id INT,
    product_id INT,
    random INT,
    UNIQUE KEY (attribute_id,random,product_id),
    KEY (product_id)
);

random是一个随机整数,用于对洗牌产品的插入计算(根据我的需要,这是O.K.)。有像

这样的自联接查询
SELECT DISTINCT x.product_id
FROM attibutes x
INNER JOIN attributes y ON x.product_id=y.product_id
INNER JOIN attributes z ON x.product_id=z.product_id
WHERE x.attribute_id IN (20000085,20000090) AND
    y.attribute_id IN (10000007) AND
    z.attribute_id IN (30000050,30000040,30000012)
LIMIT 0,100;

如您所见,我想选择在每个数字范围内至少有一个属性的产品。 MySQL非常聪明地为第一个查询本身选择表别名,具体取决于UNIQUE键的选择性。正如预期的那样,由于UNIQUE键,结果按列random的顺序排序。 但是我如何建议MySQL恢复订单呢?添加ORDER BY x.random DESC时,MySQL可能会使用filesort进行排序,因为如果它使用表别名y进行基本查询(因为属性ID 10000007具有更好的选择性),则必须使用别名的{UNIQUE键} {{ 1}}。问题是:我不知道MySQL确实使用了哪个别名(它由查询优化器决定)。那么如何指定订单方向?

(我想要注意的是,该表包含大约6千万行,因此在响应时间内使用或不使用filesort)

1 个答案:

答案 0 :(得分:1)

您可以检查此版本是否更快:

SELECT a.product_id
FROM attibutes a
WHERE a.attribute_id IN (20000085, 20000090, 10000007, 30000050, 30000040, 30000012) 
GROUP BY a.product_id
HAVING SUM(a.attribute_id IN (20000085, 20000090) ) > 0 AND
       SUM(a.attribute_id IN (10000007) ) > 0 AND
       SUM(a.attribute_id IN (30000050, 30000040, 30000012) ) > 0
ORDER BY a.rand
LIMIT 0, 100;

GROUP BY应该与SELECT DISTINCT的工作量大致相同。您仍然会产生按随机数排序的开销,但有时这种表述从性能角度来看。

编辑:

如果您将随机数放在products表中,以下可能会执行您想要的操作:

select p.*
from products p
where exists (select 1 from attributes a where p.product_id = a.product_id and a.attribute_id IN (20000085, 20000090) ) and
      exists (select 1 from attributes a where p.product_id = a.product_id and a.attribute_id IN (10000007) ) and
      exists (select 1 from attributes a where p.product_id = a.product_id and a.attribute_id IN (30000050, 30000040, 30000012) )
order by p.rand
limit 5;

嗯,如果你将随机数存储在产品表中,你只需join进入你的查询并在order by中使用它。这也可能有用。