Запрос COUNT FreeText для нескольких таблиц очень медленный

StackOverflow https://stackoverflow.com/questions/1819333

Вопрос

У меня есть две таблицы:

**Product**
ID
Name
SKU

**Brand**
ID
Name

Таблица продуктов содержит около 120 тыс. записей. Таблица брендов содержит 30 тысяч записей.

Мне нужно найти количество всех продуктов, названия и бренды которых соответствуют определенному ключевому слову.

Я использую свободный текст «содержит» следующим образом:

SELECT count(*) 
FROM   Product
       inner join Brand 
         on Product.BrandID = Brand.ID
WHERE  (contains(Product.Name, 'pants') 
   or 
            contains(Brand.Name, 'pants'))

Этот запрос занимает около 17 секунд. Я перестроил индекс FreeText перед выполнением этого запроса.

Если я проверю только Product.Name. Они запрашивают менее 1 сек. То же самое, если я проверю только Brand.Name. Проблема возникает, если я использую условие ИЛИ.

Если я переключу запрос на использование LIKE:

SELECT count(*) 
FROM   Product
       inner join Brand 
         on Product.BrandID = Brand.ID
WHERE   Product.Name LIKE '%pants%'
   or 
            Brand.Name LIKE '%pants%'

Это займет 1 сек.

Я прочитал в MSDN, что: http://msdn.microsoft.com /en-us/library/ms187787.aspx

  

Для поиска по нескольким таблицам используйте   присоединенная таблица в предложении FROM для   поиск по набору результатов, который является   произведение двух или более таблиц.

Итак, я добавил INNER JOINED таблицу в FROM:

SELECT count(*) 
FROM   (select Product.Name ProductName, Product.SKU ProductSKU, Brand.Name as BrandName FROM Product
       inner join Brand 
         on product.BrandID = Brand.ID) as TempTable
WHERE  

     contains(TempTable.ProductName, 'pants') 
     or 
            contains(TempTable.BrandName, 'pants') 

Это приводит к ошибке: Невозможно использовать предикат CONTAINS или FREETEXT для столбца «ProductName», так как он не полнотекстовый.

Итак, вопрос в том, почему условие ИЛИ может быть причиной медленного запроса?

Это было полезно?

Решение

После небольшой пробной версии я нашел решение, которое, кажется, работает. Это включает в себя создание индексированного представления:

CREATE VIEW [dbo].[vw_ProductBrand]
WITH SCHEMABINDING
AS
SELECT     dbo.Product.ID, dbo.Product.Name, dbo.Product.SKU, dbo.Brand.Name AS BrandName
FROM         dbo.Product INNER JOIN
                      dbo.Brand ON dbo.Product.BrandID = dbo.Brand.ID

GO

CREATE UNIQUE CLUSTERED INDEX IX_VW_PRODUCTBRAND_ID 
    ON vw_ProductBrand (ID);
GO

Если я выполню следующий запрос:

DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
GO

SELECT count(*) 
FROM   Product
       inner join vw_ProductBrand
         on Product.BrandID =  vw_ProductBrand.ID
WHERE  (contains(vw_ProductBrand.Name, 'pants') 
   or 
            contains( vw_ProductBrand.BrandName, 'pants'))

Теперь это снова занимает 1 секунду .

Другие советы

Вы пробовали что-то вроде:

SELECT count(*) 
    FROM Product
    INNER JOIN Brand ON Product.BrandID = Brand.ID
    WHERE CONTAINS((Product.Name, Brand.Name), 'pants') 

Я столкнулся с подобной проблемой, но я исправил ее с помощью союза, что-то вроде:

SELECT *
FROM   Product
       inner join Brand 
         on Product.BrandID = Brand.ID
WHERE contains(Product.Name, 'pants') 

UNION

SELECT *
FROM   Product
       inner join Brand 
         on Product.BrandID = Brand.ID
WHERE contains(Brand.Name, 'pants'))
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top