Freetext consulta contar com várias tabelas é super lento
-
10-07-2019 - |
Pergunta
Eu tenho duas tabelas:
**Product**
ID
Name
SKU
**Brand**
ID
Name
mesa O produto tem cerca de 120K registros mesa marca tem 30K registros
Eu preciso encontrar contagem de todos os produtos com nome e marca combinando uma palavra-chave específica.
Eu uso freetext 'contém' assim:
SELECT count(*)
FROM Product
inner join Brand
on Product.BrandID = Brand.ID
WHERE (contains(Product.Name, 'pants')
or
contains(Brand.Name, 'pants'))
Esta consulta leva cerca de 17 segundos. Eu reconstruído o índice freetext antes de executar essa consulta.
Se eu só verificar Product.Name. Eles consulta é inferior a 1 segundo. Mesmo, se eu só verificar o Brand.Name. O problema ocorre se eu usar ou condição.
Se eu mudar consulta para usar como:
SELECT count(*)
FROM Product
inner join Brand
on Product.BrandID = Brand.ID
WHERE Product.Name LIKE '%pants%'
or
Brand.Name LIKE '%pants%'
É preciso 1 seg.
Eu li no MSDN que: http://msdn.microsoft.com /en-us/library/ms187787.aspx
Para pesquisar em várias tabelas, use um juntou tabela em sua cláusula FROM para pesquisar em um conjunto de resultados que é o produto de duas ou mais tabelas.
Então eu adicionei uma tabela unida interior para 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')
Isso resulta em erro: não pode usar um CONTÉM ou predicado FREETEXT na coluna 'ProductName' porque não é indexado por texto total.
Então a questão é - por que OR condição poderia estar causando tais como consulta lenta ??p>
Solução
Depois de um pouco de tentativa um erro eu encontrei uma solução que parece funcionar. Ela envolve a criação de uma exibição indexada:
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
Se eu executar a consulta a seguir:
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'))
Agora leva 1 seg novamente.
Outras dicas
Você tentou algo como:
SELECT count(*)
FROM Product
INNER JOIN Brand ON Product.BrandID = Brand.ID
WHERE CONTAINS((Product.Name, Brand.Name), 'pants')
Eu tive um problema semelhante, mas eu fixa-lo com a união, algo como:
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'))