是否可以避免这种查询的子查询?

Posted

技术标签:

【中文标题】是否可以避免这种查询的子查询?【英文标题】:Is it possible to avoid subqueries for this kind of query? 【发布时间】:2016-06-20 04:43:56 【问题描述】:

假设我有一张包含此类数据的表格:

Parent  Value           DateFor       ValueType
3177    50.110000       2016-03-05    1
3177    254390.000000   2016-03-05    2
3177    50.110000       2016-03-06    1
3177    254390.000000   2016-03-06    2
3294    40.800000       2016-03-05    1
3294    20280.000000    2016-03-05    2

Parent 列的帮助下,我的表在 Id 上具有 PRIMARY 索引(此处未显示 id)和与父表的 FOREIGN 关系。

我想为每个父级按值类型选择最新值:

3177    50.110000       2016-03-06    1
3177    254390.000000   2016-03-06    2
3294    40.800000       2016-03-05    1
3294    20280.000000    2016-03-05    2

说明:我忽略了父 3177 的 2015-03-05 的两个值,因为它有 2016-03-06 的数据。但我从 2016-03-05 获取父级 3294 的数据,因为它是我拥有的最新数据。

实现这一目标的最高效查询是什么?因为我的表有数百万行...

是否可以避免子查询?

【问题讨论】:

How to optimize performance for this query? 查询在哪里? 哪个数据库引擎? @lad2025 我有基本的SELECT 和 where 过滤器,我提供一个父级并且没有分组,但我不知道如何构建没有过滤器和分组的查询,占据前 1按日期,所有数据... @trincot:SQL Server,对不起 它太宽泛了。首先,您的数据将其采样到很小,并且有点不清楚。其次,您没有向我们展示您的表/索引结构。第三:为什么要存储重复项? 【参考方案1】:

这个问题过于宽泛,因此答案有点笼统。使用带子查询的 SQL 查询或临时表(后者可能会带来更好的性能)。首先,通过SELECT MAX(DateFor) as MinDate FROM [YourTable] Group BY [Parent], [ValueType] 获取最早日期(最小值),然后在WHERE 子句中使用MinDate 运行第二个SELECT 语句。希望这会有所帮助。

【讨论】:

【参考方案2】:

另一种可能也具有良好性能的方法是:

SELECT [Parent], [Value], [DateFor], [ValueType]
FROM t
WHERE DateFor = (SELECT MAX(t2.DateFor)
                 FROM t t2
                 WHERE t2.Parent = t.Parent AND t2.ValueType = t.ValueType
                );

这需要 Joachim 建议的相同索引。在某些情况下,这可能会稍微快一些。您可以在数据上测试这两者。

【讨论】:

【参考方案3】:

使用分析函数和覆盖索引应该可以在牺牲一些磁盘空间的情况下获得良好的性能;

CREATE INDEX ix_test 
       ON myTable([Parent], [ValueType], [DateFor] DESC) INCLUDE ([Value]);

GO

SELECT [Parent], [Value], [DateFor], [ValueType]
FROM (
  SELECT *, ROW_NUMBER() 
            OVER (PARTITION BY [Parent], [ValueType] ORDER BY [DateFor] DESC) rn
  FROM myTable
) z
WHERE rn=1;

【讨论】:

谢谢,这看起来很棒!问题:为什么INCLUDE ([Value]) 而不是将[Value] 放入索引本身(与ON 子句中的其他列一起)? @ibiza 在这里你可以使用任何一个,INCLUDE 往往会节省一些空间。有关更多详细信息,您可以查看here。

以上是关于是否可以避免这种查询的子查询?的主要内容,如果未能解决你的问题,请参考以下文章

SELECT 中的子查询或 JOIN 中的子查询?

子查询分解问题

Select查询Ms访问中的子查询

来自 LeftJoin 的 MAX() 值的子查询

避免“不支持这种类型的相关子查询模式”的方法

是不是真的可以到处使用JOINS来代替SQL中的子查询