Query1使用Query2加入但Query2使用Query1的结果,如何只使用1个查询?

时间:2014-03-05 01:25:58

标签: mysql sql greatest-n-per-group

好的,我有一个复杂的查询来获取所有文章的详细信息,每篇文章都有很多版本。我需要获得仅包含最新版本的文章的详细信息(即采用最大版本)。这是表格:

+------------+-----------+----------+
| ArticleID  |  Detail   |  Version |
+------------+-----------+----------+
| 1          |  detail1  |  1       |
| 1          |  detail2  |  1       |
| 1          |  detail3  |  2       |
| 1          |  detail4  |  2       |
| 3          |  detail3  |  2       |
| 3          |  detail6  |  2       |
| 3          |  detail4  |  3       |
+------------+-----------+----------+

现在用户只提供一个细节&该查询将使用version=max(version)

获取所有文章的所有详细信息

假设如果我们不关心max version,那么简单的查询可能是

Select * from articleTb where Detail like '%3'

它会打印出来:

+------------+-----------+----------+
| ArticleID  |  Detail   |  Version |
+------------+-----------+----------+
| 1          |  detail3  |  2       |
| 3          |  detail3  |  2       |
+------------+-----------+----------+

但这不符合要求,因为结果不应该有此记录3 - detail3 - 2因为它不包含articleID=3的最大版本。

假设用户搜索Detail like '%4',那么正确的查询应为:

ArticleID - Detail - Version
+----+-----------+----+
| 1  |  detail4  |  2 |
+----+-----------+----+
| 3  |  detail4  |  3 |
+----+-----------+----+

这2条记录显示属于带有最高版本的文章。解释,2是articleID=1的maxversion,因此它符合条件,& 3是articleID=3的最大版本,因此它也符合条件。

所以这就是我所做的,

select * from (Select * from articleTb where Detail like '%3') tb1
Join (select articleID, max(version) maxversion from articleTb where 
Detail like '%3' group by articleID) tb2
on tb1.articleID=tb2.articleID and tb1.version=tb2.maxversion

但是,对于上述查询,系统必须复制不好的任务where Detail like '%3'。此外,我的真实世界query1比where Detail like '%3'复杂得多,那么如果我喜欢上述内容,那么查询将实现相同的工作TWICE? &安培;这是非常低效的。

那么如何解决这个问题?

4 个答案:

答案 0 :(得分:2)

要提高性能,请删除不必要的内联视图,例如

SELECT tb1.*
  FROM articleTb tb1
  JOIN ( SELECT b.articleID
              , MAX(b.version) AS maxversion
           FROM articleTb b 
          WHERE b.Detail LIKE '%3'
          GROUP BY b.articleID
       ) tb2
    ON tb1.articleID = tb2.articleID 
   AND tb1.version = tb2.maxversion
 WHERE tb1.Detail LIKE '%3'

和...

确保您有适当的索引。带有文章前导列的覆盖索引可以使MySQL使用索引来优化GROUP BY(避免“使用filesort”操作。)

... ON articleTb (articleID, version, detail)

MySQL也可以将该索引用于tb1的连接;派生表(内联视图)将没有索引。

您可以使用EXPLAIN确认执行计划。

答案 1 :(得分:1)

我会使用CTE创建一个包含文章ID和版本ID的表,然后在我的主查询中使用它来过滤到最新版本。

with latest as
(
  select articleId, max(version) as version from articleTb
)

select ....
from articleTb a
inner join latestl on a.articleid = l.articleid and l.version = a.version

答案 2 :(得分:1)

使用聚合表会有所帮助。     让我先描述一个场景。第1天,你第一次得到一个平面文件。

1. Load that in a staging table.
2. Find ArticleID, MAx (Version) for each Article ID, and store in the aggregate table.
3. Left outer join the stage table with the aggregate table joining on article ID. Pick the higher version. This will lead to your result.
4. Truncate the staging table.

第二天,当新的Feed到达时,该文件将再次加载到截断的表中,并保持连接状态。

您可以在聚合表中添加一些审核字段,例如该文件到达时的日期,也可以是文件名。我曾在保险公司的一个项目中使用过这种方法,从而获得了多倍的性能提升。

答案 3 :(得分:1)

这是您的查询:

select *
from (Select * from articleTb where Detail like '%3'
     ) tb1 Join
     (select articleID, max(version) maxversion
      from articleTb
      where Detail like '%3'
      group by articleID
     ) tb2
     on tb1.articleID=tb2.articleID and tb1.version=tb2.maxversion;

您正在尝试获取特定类型文章的最新版本。另一种方法是使用not exists

select *
from articleTb t
where Detail like '%3' and
      not exists (select 1
                  from articleTb t2
                  where t2.articleID = t1.articleID and
                        t2.Detail like '%3'
                        t2.version > t.version
                 );

这是说:"从articleTb Detail 3结束articleTb(articleID, Detail, version)并且没有更高版本的其他版本来获取所有行"

要提高效果,请在t2.Detail like '%3'上创建索引。一个问题是子查询是否需要articleTb(articleID, version) - 是否条件过滤文章中的文章或版本?如果不需要,则删除索引并将条件更改为{{1}}。

相关问题