【问题标题】:Theoretical search function in SQL/C#SQL/C#中的理论搜索功能
【发布时间】:2015-08-12 23:52:43
【问题描述】:

我正在用 SQL/C# 实现用户搜索功能。我在函数本身的后勤方面遇到了一些问题,我正在寻找一些指导。

我一直在使用三重嵌套子查询,我觉得它的运行速度有点慢(从用户表中的 1000 条记录中提取结果平均需要 280-300 毫秒)。

我首先想按属性搜索用户(单独的表),然后根据位置搜索。然后我想要计算和排序距离,然后一次只带回最近的 10 条记录(分页结果)。

我使用三重嵌套子查询的方法是否正确?或者是否有标准或指导原则来做这种(双关语不是故意的)事情?

代码示例:

SELECT * FROM
    (SELECT *, ROW_NUMBER()                 
        OVER (ORDER BY UsersSubquery.Distance ASC) as RowNumber  
        FROM

    (

        SELECT TOP 100 PERCENT UsersSubquery.*, 

         (((geography::Point(UsersLocationsSubquery.Latitude, UsersLocationsSubquery.Longitude, 4326)).STDistance(@a)) / 1000) AS Distance      

        FROM Users UsersSubquery 

            INNER JOIN UsersAndAttributes ON UsersSubquery.UserId = UserAndAttributes.UserId

            INNER JOIN UsersAndLocations AS UsersWithLocationsSubquery  ON UsersSubquery.UserId = UsersWithLocationsSubquery.UserId

        WHERE 
        ( 

            ((@Attribute1 = NULL) OR (UsersSubquery.Attribute1Id = @Attribute1)) 
            AND
            ((@Attribute2 = NULL) OR (UsersSubquery.Attribute2Id = @Attribute2)) 
            AND
            ((@Attribute3 = NULL) OR (UsersSubquery.Attribute3Id = @Attribute3)) 
            AND
            ...etc

        )


    )

    AS UsersSubquery )

Users

    INNER JOIN Pictures ON Users.UserId = Pictures.UserId

WHERE RowNumber >= @StartRow and RowNumber <= @EndRow 

Order by RowNumber

【问题讨论】:

  • 你能告诉我们你正在使用的查询吗?
  • 这太模糊了,无法得到任何有用的答案。我们不知道您的表的结构、它的索引方式、您的查询是什么,或者其他任何事情。请发布一些代码,否则我们无法帮助您。
  • 是的,我认为这会出现。暂时...
  • 也许我应该问,临时视图是否优于多个子查询?
  • 只要不影响结果集,SQL 引擎可以随意对查询的各个部分进行重新排序。它可能不会按照您编写代码的顺序执行操作。查询计划将准确显示它执行操作的顺序以及哪些步骤很慢。

标签: c# sql tsql search


【解决方案1】:

因为您想要分页数据,这意味着您需要过滤 ROW_NUMBER() 值,该值需要按Distance 计算排序,您将需要 3 个嵌套子查询。不过,我确实认为它可以做得更干净一些。

我不确定您为什么要从您的内心查询中获取TOP 100 PERCENT,因为这实际上不会做任何事情。我只能假设您在某一时刻订购了该内部查询并使用 TOP 子句使其不会出错。 这行不通,而且结果的顺序也无法保证。所以看起来你从那以后走了一条不同的路,这很好。

您在查询中使用别名的方式也有点令人困惑。在最里面的查询中,您将实际的User 表别名为UsersSubquery,然后您为后面的子查询使用了相同的名称。最后,您将最外层的子查询别名为Users,它与基表同名。

没有理由不在您进行其他联接的同时加入Pictures 表。该连接和最里面的查询(它有过滤用户属性的WHERE 子句)之间没有任何额外的过滤,因此执行连接将是同样的事情。

这就是我编写查询的方式:

DECLARE @RowsToFetch INT = 10;

SELECT TOP (@RowsToFetch) *
FROM (
    SELECT *,
        ROW_NUMBER() OVER (ORDER BY Distance ASC) AS RowNumber
    FROM (
        SELECT Users.*,
            (((geography::Point(UsersAndLocations.Latitude, UsersAndLocations.Longitude, 4326)).STDistance(@a)) / 1000) AS Distance
        FROM Users
        INNER JOIN UsersAndAttributes ON Users.UserId=UsersAndAttributes.UserId
        INNER JOIN UsersAndLocations ON Users.UserId=UsersAndLocations.UserId
        INNER JOIN Pictures ON Users.UserId=Pictures.UserId
        WHERE (@Attribute1 = NULL OR UsersAndAttributes.Attribute1Id = @Attribute1)
            AND (@Attribute2 = NULL OR UsersAndAttributes.Attribute1Id = @Attribute2)
            ..etc
    ) AS UsersData
) AS UsersNumbered
WHERE RowNumber >= @StartRow
ORDER BY RowNumber

最后,我实际上会在查询中的任何地方使用SELECT *(尤其是最里面的子查询)。相反,只选择您需要的特定列。这将有助于减少 SQL Server 需要做的工作量,并减少返回结果时需要通过网络传输的数据量。我不知道您需要哪些列,所以我重新使用了您的 SELECT *。

【讨论】:

  • 好的,我想知道您的所有个人观点。 TOP 100 PERCENT 是专门为了避免错误,正确的。但是,我没有订购内部查询。我试图在最里面的查询中避免Pictures 表上的INNER JOIN,因为它会为所有符合属性条件的用户提取所有图片数据。为什么不以某种方式为外部查询提取数据?我可以采取另一种方法吗?这个查询的平均时间约为 280-300 毫秒,我真的觉得我可以让它运行得更快。查询时间长吗?
  • 你在程序上考虑得太多了。优化器可能不会完全按照您的布局执行查询。相反,它会尝试找到最有效的方法来获得您所追求的结果集。为此,我认为在内部或外部加入图片表不会有很大的不同。另一方面,在结果集中恢复图片数据会减慢速度,因为它需要通过网络传输所有数据。我很好奇在不返回二进制图像数据的情况下查询有多快。
  • 您试图通过包含 TOP 100 PERCENT 来阻止什么错误?我知道的唯一解决方法是尝试订购子查询或视图(它不起作用)。此外,如果您想加快查询速度,限制查询返回的列数也是一个不错的起点。您必须通过网络从 SQL 服务器推送到客户端的数据越少越好。恕我直言,我可以接受 1/3 秒的查询结果。您的功能需求真的需要它比这更快吗?
猜你喜欢
  • 2011-06-24
  • 1970-01-01
  • 1970-01-01
  • 2018-10-17
  • 1970-01-01
  • 1970-01-01
  • 2013-10-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多