Запрос COUNT FreeText для нескольких таблиц очень медленный
-
10-07-2019 - |
Вопрос
У меня есть две таблицы:
**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'))