Pregunta

Tengo dos tablas:

**Product**
ID
Name
SKU

**Brand**
ID
Name

La tabla de productos tiene aproximadamente 120K registros La tabla de marcas tiene 30K registros

Necesito encontrar el recuento de todos los productos con nombre y marca que coinciden con una palabra clave específica.

Uso el texto libre 'contiene' como este:

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

Esta consulta lleva unos 17 segundos. Reconstruí el índice de FreeText antes de ejecutar esta consulta.

Si solo busco Product.Name. Ellos consultan menos de 1 seg. Lo mismo, si solo verifico el Brand.Name. El problema ocurre si uso la condición OR.

Si cambio la consulta para usar LIKE:

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

Tarda 1 segundo.

Leí en MSDN que: http://msdn.microsoft.com /en-us/library/ms187787.aspx

  

Para buscar en varias tablas, use un   tabla unida en su cláusula FROM a   buscar en un conjunto de resultados que es el   producto de dos o más mesas.

Entonces agregué una tabla INNER JOINED a 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') 

Esto produce un error: No se puede usar un predicado CONTAINS o FREETEXT en la columna 'ProductName' porque no está indexado a texto completo.

Entonces la pregunta es: ¿por qué la condición OR podría estar causando, como una consulta lenta?

¿Fue útil?

Solución

Después de un poco de prueba y error, encontré una solución que parece funcionar. Implica crear una vista indizada:

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

Si ejecuto la siguiente consulta:

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'))

Ahora toma 1 segundo nuevamente.

Otros consejos

¿Has probado algo como:

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

Me encontré con un problema similar pero lo solucioné con union, algo así 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'))
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top