2

ユーザー検索の上位結果のフルテキスト インデックスを含むテーブルに対してクエリを実行し、その末尾にワイルドカード検索の結果を追加しています。

これが私の少し単純化されたSQLです...

SELECT TOP(@top) * FROM     
(       
    SELECT TOP (@top) ft.[RANK], p.ProductID, p.Name FROM dbo.Product p 
    INNER JOIN FREETEXTTABLE(dbo.Product, *, @search_term) AS ft ON p.ProductID = ft.[KEY]
    ORDER BY ft.[RANK] * p.Popularity DESC

    UNION ALL

    SELECT TOP (@top) 0 AS [RANK], p.ProductID, p.Name FROM dbo.Product p 
    WHERE (NOT p.ProductID IN (SELECT [KEY] FROM FREETEXTTABLE(dbo.Product, *, @search_term)))
    AND   (p.Name LIKE '%' + @search_term + '%')
    ORDER BY p.Popularity DESC
) AS results

これはすべて機能し、しばらくの間稼働しています。

ここがトリッキーな部分です。最近、これが Web サイトで最もコストのかかるクエリの 1 つであることを発見しました。クエリ プランを調べたところ、クエリの LIKE '%%' 部分で 50 ~ 80% のコストが発生していることがわかりました。ワイルドカード検索は遅くなる傾向があるため、これは大きな驚きではありません。問題は、UNION ALL の前半がそれだけで十分な行を返したときに、UNION ALL の後半を実行する必要がないことです。

前半 (全文検索) で必要なすべての行が返されたときに、UNION ALL を実行しない方法はありますか?

4

2 に答える 2

3

あなたはこのようにそれを行うことができます:

SELECT TOP (@top) ..., ft.[RANK] * p.Popularity INTO #foo ... <FT query>;

IF @@ROWCOUNT < @top
  INSERT #foo SELECT TOP (@top) ..., p.Popularity FROM <like query>;

SELECT TOP (@top) ... FROM #foo ORDER BY Popularity DESC;

もう少しI/Oですが、オフセットする価値があるかもしれません。

また、最初のクエリをクライアントに返し、最初のクエリでは不十分な場合にのみ2番目の結果セットを返し、アプリケーションをスマートにして結果セットをマージすることを検討することもできます。これは、ft。[RANK] * p.Popularityだけでランク付けされた結果の前に、 ft。[RANK]*p.Popularityを表示することを目的としている場合にのみ機能します。

于 2012-06-29T14:03:22.380 に答える
0

1つのステートメントでそれを実行できる方法はわかりませんが@@rowcount、最初のクエリの後で確認し、十分に高くない場合にのみ2番目のクエリを実行できます。

于 2012-06-29T14:03:44.470 に答える