1

我想查找以在搜索框中输入的字符开头的地理名称。一些地理名称在其他语言中有替代名称。这些替代名称存储在单独的表中。

GN_Name 1 - 0:N GN_AlternateName

(PK)GN_Name.GeoNameId == (FK)GN_AlternateName.GeoNameId

我想先在 GN_AlternateName.AlternateName 中搜索名称,如果不存在,请使用相应的 GN_Name.Name。

我写了以下 LINQ 查询:

return (from name in db.GN_Name
        where name.CountryCode == "se"
        join alt in db.GN_AlternateName 
        on name.GeoNameId equals alt.GeoNameId into outer
        from alt in outer.DefaultIfEmpty()
        where ((alt.IsoLanguage == "sv" && 
                alt.AlternateName.StartsWith(query)) || 
                name.Name.StartsWith(query))
        select new GeoNameModel { 
            Language = alt.IsoLanguage, 
            Name = (alt == null ? name.Name : alt.AlternateName),
            FeatureClass = name.FeatureClass, 
            FeatureCode = name.FeatureCode, 
            GeoNameId = name.GeoNameId, 
            UniqueName = name.UniqueName,
            UniqueCount = name.UniqueCount}).Take(HB.AutoCompleteCount);

这转化为以下 SQL:

exec sp_executesql N'SELECT 
[Limit1].[GeoNameId] AS [GeoNameId], 
[Limit1].[IsoLanguage] AS [IsoLanguage], 
[Limit1].[C1] AS [C1], 
[Limit1].[FeatureClass] AS [FeatureClass], 
[Limit1].[FeatureCode] AS [FeatureCode], 
[Limit1].[UniqueName] AS [UniqueName], 
[Limit1].[UniqueCount] AS [UniqueCount]
FROM ( SELECT TOP (5) 
    [Extent1].[GeoNameId] AS [GeoNameId], 
    [Extent1].[FeatureClass] AS [FeatureClass], 
    [Extent1].[FeatureCode] AS [FeatureCode], 
    [Extent1].[UniqueName] AS [UniqueName], 
    [Extent1].[UniqueCount] AS [UniqueCount], 
    CASE WHEN ([Extent2].[AlternateNameId] IS NULL) THEN [Extent1].[Name] ELSE [Extent2].[AlternateName] END AS [C1], 
    [Extent2].[IsoLanguage] AS [IsoLanguage]
    FROM  [dbo].[GN_Name] AS [Extent1]
    LEFT OUTER JOIN [dbo].[GN_AlternateName] AS [Extent2] ON [Extent1].[GeoNameId] = [Extent2].[GeoNameId]
    WHERE (''se'' = [Extent1].[CountryCode]) AND (((''sv'' = [Extent2].[IsoLanguage]) AND ([Extent2].[AlternateName] LIKE @p__linq__0 ESCAPE N''~'')) OR ([Extent1].[Name] LIKE @p__linq__1 ESCAPE N''~''))
)  AS [Limit1]',N'@p__linq__0 nvarchar(4000),@p__linq__1 nvarchar(4000)',@p__linq__0=N'ja%',@p__linq__1=N'ja%'

我真的看不出它有什么问题,但大约需要 5 秒才能完成。

我应该添加一些索引吗?也许设置一个索引视图?我的 SQL 服务器知识有限,我很想回到一些真正的编码;)

任何建议热烈赞赏!

更新 我正在使用 SQL Server 2008。按照 taylonr 的说明,我得到了以下结果。 客户统计 执行计划 执行计划详情

有 3 个“部分”占总数的 100%。但是,我不知道如何使用这些统计数据。

更新 2

SSMS 执行计划推荐以下指标:

CREATE NONCLUSTERED INDEX IX_GN_Name_CountryCode
ON [dbo].[GN_Name] ([CountryCode])
INCLUDE ([GeoNameId],[Name],[FeatureClass],[FeatureCode],[UniqueName],[UniqueCount])

我添加了它,现在查询运行得更好了!

UPDATE 3 taylonr 建议只使用一个 LIKE 子句。我不确定如何做到这一点。有人愿意挑战吗?

4

5 回答 5

3

首先,我会小心称 SQL 不是“真正的编码”,因为看起来改进可以帮助你;)(我是 C# 人,而不是 SQL 专家,只是说......)

进入您的 SSMS,并获取生成的查询。

将其复制到新的查询窗口中。

现在在运行之前做两件事。1. 进入查询菜单并点击“包括客户统计” 2. 进入查询菜单并点击“包括实际执行计划”

现在运行您的查询。

查询完成后,检查标记为“等待服务器回复的时间”项的客户端统计信息,这是服务器为此查询执行的时间量(以毫秒为单位)。

“总执行时间”是客户端和服务器通信数据所花费的时间。

这将使您了解服务器上的时间。例如,如果这是 10 毫秒,并且从您的代码执行需要 5 秒,那么 Sql 可能不是问题。

接下来,打开您的执行计划选项卡。这将向您展示 SQL 如何生成此数据。例如,如果它花费 100% 的时间进行表扫描(而不是索引扫描),那么您可能需要添加一些索引。

查看执行计划并查看百分比最高的内容。这将使您了解可以优化查询的位置。

我猜想拥有两个单独的“喜欢”语句可能没有多大帮助。Like 语句的性能不如相等,例如

WHERE name = 'taylonr'

WHERE name like 'taylo%'
于 2011-03-31T21:45:01.857 回答
1

您可以在Database Engine Tuning Advisor中运行查询。

它会在分析查询后提出索引建议。

于 2011-03-31T21:37:19.587 回答
0

您可以尝试将其分解为 3 个左右的单独请求吗?然后看看有没有一个异常长。将你所有的工作都放在一个 return() 中,这使得诊断事情变得非常困难。

于 2011-03-31T21:34:35.323 回答
0

我认为问题在于 EF 正在将您的参数 @p_ linq _1 nvarchar(4000) 转换为 nvarchar,我的猜测是它们在数据库中存储为 varchar 强制 sql server 强制转换它们。

我遇到了同样的问题。尝试在查询分析器中运行 sql,并将参数的类型更改为 varchar,看看它是否运行得更快。

于 2011-03-31T21:45:39.770 回答
0

可能有帮助的一件事是,如果翻译的 from 子句看起来像这样

FROM [dbo].[GN_Name] AS [Extent1] 
LEFT OUTER JOIN [dbo].[GN_AlternateName] AS [Extent2] 
ON [Extent1].[GeoNameId] = [Extent2].[GeoNameId]) AS [Limit1] 
AND ( 'sv' = [Extent2].[IsoLanguage] ) 

我猜这意味着 linq 会在这里。

join alt in db.GN_AlternateName 
on name.GeoNameId equals alt.GeoNameId && alt.IsoLanguage == 'sv'

另外我会考虑以下字段的索引。但是 Tuning Advisor 确实应该以一种或另一种方式告诉您。

GN_Name.GeoNameId
GN_AlternateName.GeoNameId
GN_Name.CountryCode
GN_Name.Name
GN_AlternateName.AlternateName
于 2011-03-31T22:35:14.813 回答