2

我在合理的时间内从具有 2M 行的表中获取前 100 行时遇到问题。问题是按部分排序,需要 50 多分钟才能得到这个查询的结果。这个问题的最佳解决方案是什么?

select top 100 * from THETABLE TT
Inner join SecondTable ST on TT.TypeID = ST.TypeID
ORDER BY DATEDIFF(Day, TT.LastCheckDate, GETDATE()) * ST.SomeParam DESC

非常感谢,

本齐

编辑:* TheTable 是具有 2M 行的表。* SomeParam 有 15 个不同的值(或多或少)

4

5 回答 5

0

为了减少行数,您可以为SecondTable按 LastCheckDate 排序的每条记录检索前 (100) 行,然后通过临时表或动态 sql 生成的查询将它们合并,最后选择前 (100)。

此解决方案使用游标获取 SecondTable 中每个值的前 100 条记录。使用 TheTable 上的 (TypeID, LastCheckDate) 索引,它会立即运行(在我的系统上使用包含 700,000 条记录和 50 个 SecondTable 条目的表进行测试)。

declare @SomeParam varchar(3)
declare @TypeID int

declare @tbl table (TheTableID int, LastCheckDate datetime, SomeParam float)

declare rstX cursor local fast_forward for
      select TypeID, SomeParam
        from SecondTable

open rstX
while 1 = 1
begin
    fetch next from rstX into @TypeID, @SomeParam
    if @@fetch_status <> 0
       break
    insert into @tbl
    select top 100 ID, LastCheckDate, @SomeParam
      from TheTable
     where TypeID = @TypeID
     order by LastCheckDate
end
close rstX
deallocate rstX

select top 100 *
from @tbl
order by DATEDIFF(Day, LastCheckDate, GETDATE()) * SomeParam

显然,此解决方案仅获取 ID。您可能希望使用其他列来扩展临时表。

于 2012-07-26T15:06:04.043 回答
0

想到两个想法:

a)如果 ST.param 不经常更改,也许您可​​以在某处缓存乘法的结果。一天后数字将“关闭”,但相对值将相同 - 即,排序顺序不会改变。

b) 找到减小输入表大小的方法。LastCheckDate 和/或 SomeParam 的某些值可能永远不会进入前 100 名。例如,

Select * 
into #tmp 
from THETABLE 
where LastCheckDate between '2012-06-01' and getdate()


select top 100 *
from #tmp join SecondTable ST on #tmp.TypeID = ST.TypeID
order by DateDiff(day, LastCheckDate, getdate()) * ST.SomeParam desc

搜索一张小桌子比搜索一张大桌子要快得多。

于 2012-07-26T14:36:02.237 回答
0

为了加快获取速度,我想到了两件事:

  1. 如果您需要经常运行此查询,则应为“lastCheckDate”列编制索引。无论您使用哪个 sql db,列上定义明确的索引都将允许更快的选择,尤其是在 order by 子句中。

  2. 在执行选择查询之前执行日期数学。您将获得行的 checkDate 和当前日期之间的天数差,乘以某个参数。乘法会影响行的顺序吗?这可以简单地由'lastCheckDate desc'订购吗? 探索返回相同结果的其他排序选项。

于 2012-07-26T14:25:07.447 回答
0

这很复杂。您真的需要查询中的所有列吗?您可以在这里尝试一件事。首先只需获取前 100 行 typeid

像下面的东西

select top 100 typeid
,TT.lastcheckdate,st.someparam --do not use these if the typeid is unqiue in both tables..
--or just the PK columns of both tables and typeid so that these can be joined on PK
into #temptable
from st inner join tt on st.typeid = tt.typeid 
ORDER BY DATEDIFF(Day, TT.LastCheckDate, GETDATE()) * ST.SomeParam DESC 

上面将对非常少的数据进行排序,因此应该更快。根据表和索引中有多少列,这应该会更快(如果两个表中都有很多列,它会很快,但是这个查询将只使用 3。此外,也许这些列(st.typeid、st.someparam 和 tt.typeid 和 tt.lastcheckdate)被一些索引覆盖,因此不需要读取底层表,从而也减少 IO)而不是实际的列。然后加入此数据返回到两个表。

如果这不能按您期望的方式工作。那么您可以通过将表达式的顺序添加为列来使用上面的选择来索引视图。然后使用这个索引视图获得前 100 名并与主表连接。这肯定会减少工作量,从而提高性能。但是索引视图会有开销,这取决于表 TT 中数据更改的频率。

于 2012-07-26T14:59:59.647 回答
0

DATEDIFF(Day, TT.LastCheckDate, GETDATE())是自“上次检查”以来的天数。

如果您只是订购,TT.LastCheckDate您会得到类似的订单。

编辑 也许您可以计算出您不希望返回的日期并对其进行过滤。当然,您还需要该 LastDateCheck 列上的索引。如果一切顺利,您至少可以将要检查的记录列表从 2M 缩短到可管理的数量。

于 2012-07-26T14:22:25.447 回答