【问题标题】:Order SQL statement by count of sub-records efficiently (MS-SQL)按子记录数高效排序 SQL 语句 (MS-SQL)
【发布时间】:2019-08-28 13:41:10
【问题描述】:

我有一个包含两列的表,一个 ID 和一个序列号。让我们将此表称为vehicle。序列号用于自动完成文本框。现在,我只是用 contains/like 语句缩小列表并选择前 5 个匹配项。显然,这会返回 5 个最旧的记录。

这些车辆条目由另一个表通过外键引用。让我们称之为appearence。为了改善用户体验,我想展示过去三个月中出现频率最高的五辆汽车。

一个简单的方法是,简单地将两个表连接在一起,按序号分组,统计指定时间范围内出现的次数,最后按该次数降序排列。

问题是,这个自动完成的文本框被访问得比较频繁,所以我想知道,是否有针对这个的内置优化。我的第一个想法是,创建一个日常工作,更新一个新的probability 列并按该列排序。我还看到了 SQL Server Management Studio 中的统计选项,我想知道这是否对我有帮助。还是有办法为此使用视图?

每天更新订单会很丰富。

这是 select 语句(还没有时间组件):

SELECT RegistrationNumber, count(lbt.ID) as cnt
  FROM [Trailer] t
  INNER JOIN [LoadingBay_Trailer] lbt ON t.ID = lbt.ID_Trailer
  group by t.RegistrationNumber
  order by cnt desc

【问题讨论】:

  • 您可以向我们提供样本数据和预期结果吗?请不要使用图片 - 我们需要实际数据...
  • 只是查询表太慢了吗?就目前而言,这个问题无法回答,因为它缺乏任何细节。
  • 请参阅 How to post a T-SQL question on a public forum 以获取为该问题添加必要细节的提示和工具。
  • @Birel 我已经编辑了我的帖子并添加了 SQL 语句。
  • @SeanLange 这并不慢。但它会在(共享)服务器上产生负载。而且这个软件有很多用户。

标签: sql-server sql-order-by


【解决方案1】:

目前,我已经用一个简单的视图解决了这个问题。我不喜欢这种方法,因为它会在服务器上产生大量负载,因为在用户每次击键后都会调用视图:

CREATE VIEW [dbo].[TrailerAutocompleteHelper] AS
SELECT
    t.ID,
    t.RegistrationNumber,
    t.InUse,
    ROW_NUMBER() OVER(ORDER BY COUNT_BIG(lbt.ID_Trailer) DESC, RegistrationNumber ASC) AS Probability
FROM [dbo].[AvailableTrailers] t
LEFT JOIN [dbo].[LoadingBay_Trailer] lbt ON
    t.ID = lbt.ID_Trailer AND
    lbt.Arrival > DATEADD(month, -3, GETDATE())
GROUP BY t.ID, t.RegistrationNumber, t.InUse
GO

和 C#

public async Task<List<TrailerAutocomplete>> GetTrailers(string registrationNumberPart) {
    return await mapi.db.TrailerAutocompleteHelpers
        .Where(t => t.RegistrationNumber.Contains(registrationNumberPart))
        .OrderBy(t => t.Probability)
        .Select(t => new TrailerAutocomplete() {
            ID = t.ID,
            RegistrationNumber = t.RegistrationNumber,
            InUse = t.InUse
        })
        .Take(10)
        .ToListAsync();
}

这是 Entity 框架从我的命令中得到的:

exec sp_executesql N'SELECT TOP (10) 
    [Project1].[ID] AS [ID], 
    [Project1].[RegistrationNumber] AS [RegistrationNumber], 
    [Project1].[InUse] AS [InUse]
    FROM ( SELECT 
        [Extent1].[ID] AS [ID], 
        [Extent1].[RegistrationNumber] AS [RegistrationNumber], 
        [Extent1].[InUse] AS [InUse], 
        [Extent1].[Probability] AS [Probability]
        FROM (SELECT 
    [TrailerAutocompleteHelper].[ID] AS [ID], 
    [TrailerAutocompleteHelper].[RegistrationNumber] AS [RegistrationNumber], 
    [TrailerAutocompleteHelper].[InUse] AS [InUse], 
    [TrailerAutocompleteHelper].[Probability] AS [Probability]
    FROM [dbo].[TrailerAutocompleteHelper] AS [TrailerAutocompleteHelper]) AS [Extent1]
        WHERE [Extent1].[RegistrationNumber] LIKE @p__linq__0 ESCAPE N''~''
    )  AS [Project1]
    ORDER BY [Project1].[Probability] ASC',N'@p__linq__0 nvarchar(4000)',@p__linq__0=N'%ABC%'

【讨论】:

  • 为此添加 TOP 5 以限制返回的结果数量。您需要在此处订购以确保获得正确的 5。如果您有适当的索引,这应该会非常快。
  • @SeanLange 我也添加了我的服务器端代码。它实际上是前 10 名^^
  • 我注意到它是 10。将它放在您的视图中以限制发回的数据量。此处服务器上的负载是因为您要从数据库发回所有内容,然后将大部分数据丢弃。限制源中的行数。
  • @SeanLange 不完全是。 Entity Framework其实是创建了一条语句,通过Take命令限制结果的数量。
  • 天啊,EF 生成的代码太可怕了。这里的表现至少可以说是残酷的,因为它在你的 like 谓词上有一个领先的通配符。这会扼杀你的性能和你的服务器。您可以更改它以删除前导通配符吗?
猜你喜欢
  • 2012-05-25
  • 1970-01-01
  • 1970-01-01
  • 2019-09-19
  • 2013-01-21
  • 1970-01-01
  • 2012-09-11
  • 2017-12-27
  • 1970-01-01
相关资源
最近更新 更多