SQL / C#中的理论搜索功能

时间:2015-08-12 23:52:44

标签: c# sql tsql search

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

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

我首先要按用户的属性(单独的表)进行搜索,然后根据位置进行搜索。然后,我想要计算和排序距离,然后一次只返回最接近的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

1 个答案:

答案 0 :(得分:2)

因为您想要分页数据,这意味着您需要过滤需要通过Distance计算排序的ROW_NUMBER()值,您将需要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 *