一尘不染

内部连接选择A和B上的(A,B)与MySQL中的select(A,B)中的(A,B)

sql

这两个之间最好的查询是什么?他们输出相同的结果,期望一个在a内执行条件where in,另一个在a内执行条件inner join

select uv.* from version v inner join user_version uv ON v.id=uv.version_id
WHERE (v.number, v.master_id) IN (
select max(v.number) as number, v.master_id 
  from version v inner join user_version uv ON v.id=uv.version_id group by v.master_id);

 select * from user_version uv 
   inner join version v on v.id=uv.version_id and v.number
   inner join (
      select uv2.user_id, max(v2.number) maxNumber, v2.master_id master_id, v2.id version_id from version v2 
         inner join user_version uv2 on v2.id=uv2.version_id group by v2.master_id ) test
   on test.master_id=v.master_id and test.maxNumber=v.number ;

我创建了一个带有示例的sqlfiddle:http
://sqlfiddle.com/#!2/76001/62 (这个想法是获得链接到给定用户的“主”实体的最大版本)

如果您还有其他想法(我使用的是mysql,则无法使用Windows函数)

谢谢


阅读 164

收藏
2021-05-23

共1个答案

一尘不染

要回答这个问题并不容易。您应该知道一件事:MySQL将IN (<static values list>)IN (<subquery>)视为不同的查询。第一个等于 范围比较 (如.. OR = .. OR =),而第二个等于= ANY ()-,并且不相同。因此,简而言之:IN与subquery一起使用将导致with查询,ANY()而MySQL不会为此使用index,即使subquery是独立的并返回
静态值列表 。伤心,但真实。MySQL无法预测到这一点,因此即使显而易见,也不会使用索引。如果使用JOIN(即重写IN (<subquery>)),则MySQL将使用index作为JOIN条件(如果可能)。

现在,第二种情况可能JOININ使用分区有关。如果您将使用JOIN-那么,可悲的是-但MySQLJOIN在通常情况下也无法预测分区-
它将使用整个分区集。替换JOININ (<static list>)会改变EXPLAIN PARTITION情况:MySQL将仅使用那些在IN子句中指定的从范围中选择值所需的分区。但是,这再次不适用于IN (<subquery>)

得出一个结论-令人遗憾的是,当我们谈论MySQL如何处理IN子查询时-
在通常情况下,不能JOIN安全地替换它(这是关于分区的情况)。因此,常见的解决方案是: 在应用程序级别将子查询与主查询分开
。如果我们说的是独立子查询,返回静态值列表,那是最好的建议-那么您可以将该值列表替换为asIN(<static list>)并获得好处:MySQL将为其使用索引,并且,如果我们说的是分区,则实际上从他们需要的将被使用。

2021-05-23