我的项目使用ASP.Net Core 1.1,EF Core和SQL Server数据库。
我有一个字符串数组,应该在文本字段中搜索(实际上字段是标记列表,数组是标记数组)。
完整方案:
在我的服务器端(.Net Core),我有一系列标签{'tag2','tag4'}。
每个地方都存储在SQL Server中,其中包含用逗号'tag1,tag2,tag3'分隔的标记列表。
我想获得至少匹配至少一个标签的20个最近的地方。
我考虑将数据表作为参数传递给具有自定义类型参数的SQL函数,但是直到v2时,.Net Core中还没有包含数据类型。
实体DbContext类中的C#代码类似于:
decimal lat=2.0, lng=3.0; float maxRadius=50000;
var tags = new Array<string>(){"tag1", "tag2"};
var places = await this.Set<Place>()
.FromSql("SELECT * FROM GetPlaces(@p0, @p1, @p2, @p3, @p4)", maxResults, lat, lng, maxRadius, tags).ToListAsync();
(当然不幸的是,传递这样的标签不起作用)
SQL函数将是这样的:
WITH Results as (
SELECT p.Id, p.Name
, ([geography]::Point(@lat,@lng,(4326))).STDistance(Coordinates)) AS Distance
FROM Places p
INNER JOIN ValsToSearch v
ON p.Tags LIKE '%'+v.Val+'%'
WHERE Distance < @distance
)
SELECT DISTINCT TOP(20) * FROM Results
ORDER BY Distance
这个对我来说似乎不是很有效,因为它将字段与连接相乘然后区分它们,但我不知道是否有可能使它更好。
我想获得最有效的查询来做类似的事情。
任何帮助/想法? :) 将所有内容加载到内存中是不可取的,因为数据库中有200k行(在某些区域可能非常密集)
另一种选择是在c#代码中,但由于NetCore 1.1版中不存在坐标,我不确定它是否会正确转换为SQL(CONTAINS
或LIKE
查询) :
var places = await (from p in this.Set<Place>()
.FromSql("SELECT * FROM GetClosestPlaces(@p0, @p1, @p2)", lat, lng, maxRadius)
where (from t in tags where p.Tags.Contains(t) select t).Any()
select p).Take(maxResults).ToListAsync();
使用SQL函数:
CREATE FUNCTION [dbo].[GetClosestPlaces]
(@lat decimal,@lng decimal,@maxRadius float=50000)
RETURNS TABLE AS RETURN
SELECT * FROM Places
WHERE ([geography]::Point(@lat,@lng,(4326)))
.STDistance(([geography]::Point([Latitude],[Longitude],(4326))))
< @maxDistance
任何建议?
目标是在SQL端,消耗的资源越少,并且在两端,耗时越少(服务应该给出非常快的答案,因为对于同一查询可能会多次调用)。
“此时”我在数据库中找不到任何好的解决方案。所以我用我的其他过滤器(距离)预过滤数据库数据,然后在内存中应用文本过滤器。 效率更高:SQL解决方案为500毫秒,而linq解决方案为100-150毫秒。