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 サーバーの知識は限られているので、実際のコーディングに戻りたいと思っています ;)

どんな提案でも大歓迎です!

UPDATE 私はSQLサーバー2008を使用しています.taylonrの指示に従って、次の結果を得ました。 クライアント統計 実行計画 実行計画の詳細

全体の100%を占める「パーツ」は3つ。ただし、これらの統計をどのように使用するかについての手がかりはありません。

更新 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 句を 1 つだけ使用することを提案しています。これを達成する方法がわかりません。挑戦する人はいますか?

4

5 に答える 5

3

まず、SQL を「本物のコーディング」と呼ぶことに注意する必要があります。なぜなら、改善が役立つように見えるからです ;) (私は C# の専門家であり、SQL の専門家ではありません。

SSMS にアクセスし、生成されたクエリを取得します。

それを新しいクエリ ウィンドウにコピーします。

実行する前に 2 つのことを行います。1. クエリ メニューに移動し、[クライアント統計を含める] をクリックします。 2. クエリ メニューに移動し、[実際の実行計画を含める] をクリックします。

クエリを実行します。

クエリが完了したら、「サーバー応答の待機時間」というラベルの付いた項目のクライアント統計を確認します。これは、サーバーがこのクエリを実行している時間 (ミリ秒) です。

「合計実行時間」は、クライアントとサーバーがデータを通信するのにかかった時間です。

これにより、サーバー上の時間がどのようなものかがわかります。たとえば、それが 10 ミリ秒で、コードからの実行に 5 秒かかる場合、SQL は問題ではない可能性があります。

次に、実行計画タブを開きます。これにより、SQL がこのデータをどのように生成したかがわかります。たとえば、(インデックス スキャンではなく) テーブル スキャンに 100% の時間を費やした場合は、いくつかのインデックスを追加することをお勧めします。

実行計画を見て、割合が最も高いものを確認します。これにより、クエリを最適化できる場所がわかります。

2 つの別々の 'like' ステートメントを使用しても、おそらくあまり役​​に立たないと思います。like ステートメントは、等式ほどパフォーマンスが高くありません。たとえば、

WHERE name = 'taylonr'

よりも速い

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

データベース エンジン チューニング アドバイザーでクエリを実行できます。

クエリを分析した後、インデックスの提案を行います。

于 2011-03-31T21:37:19.587 に答える
0

問題は、EF がパラメーター @p_ linq _1 nvarchar(4000) を nvarchar に変換していることだと思います。私の推測では、データベースにそれらが varchar として格納され、SQL サーバーに強制的にキャストさせていると思います。

私は同じ問題に遭遇しました。クエリ アナライザーで sql を実行し、パラメーターの型を varchar に変更して、実行速度が向上するかどうかを確認してください。

于 2011-03-31T21:45:39.770 に答える
0

役立つ可能性があることの 1 つは、変換された 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 に答える
0

これを 3 つほどの個別のリクエストに分割してみていただけますか? 次に、それらのいずれかが異常に長いかどうかを確認します。すべての作業を単一の return() に入れると、診断が非常に難しくなります。

于 2011-03-31T21:34:35.323 に答える