2009-11-30 4 views
1

J'ai deux tables:FreeText COUNT requête sur plusieurs tables est super lent

**Product** 
ID 
Name 
SKU 

**Brand** 
ID 
Name 

table produit a environ 120K enregistrements table de marque a 30K records

Je dois trouver le nombre de tous les produits avec nom et marque correspondant à un mot clé spécifique.

J'utilise FreeText 'contient' comme ceci:

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

Cette requête prend environ 17 secondes . J'ai reconstruit l'index FreeText avant d'exécuter cette requête.

Si je vérifie seulement pour Product.Name. Ils demandent moins de 1 seconde. Pareil, si je vérifie seulement le Brand.Name. Le problème se produit si j'utilise la condition OU.

Si je passe requête à utiliser LIKE:

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

Il faut 1 sec.

je lis sur MSDN: http://msdn.microsoft.com/en-us/library/ms187787.aspx

To search on multiple tables, use a joined table in your FROM clause to search on a result set that is the product of two or more tables.

J'ajouté un INNER REJOINT table DE:

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

Il en résulte une erreur: Impossible d'utiliser un prédicat CONTAINS ou FREETEXT sur colonne 'ProductName' car elle n'est pas indexée en texte intégral. Donc, la question est - pourquoi la condition OU pourrait causer une requête lente, par exemple?

+0

Avez-vous un index sur Product.BrandID? –

+0

Oui, il existe un index sur Product.BrandID. –

Répondre

2

Après un peu d'essais une erreur que je trouve une solution qui semble fonctionner. Il consiste à créer une vue indexée:

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 je lance la requête suivante:

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

Il faut maintenant 1 sec à nouveau.

+0

MERCI !! Au lieu de faire l'OR, je suis allé de l'avant et combiné tout dans une seule clause contient après avoir ajouté l'index à une vue.Fonctionne 10 fois plus vite maintenant. – NotMe

0

Avez-vous essayé quelque chose comme:

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

Je reçois une erreur: Les références de prédicat fulltext Fulltext issues de deux tables différentes ou de vues indexées 'Product' et 'Brand' ne sont pas autorisées. –

+0

Oh bien; ça valait le coup d'essayer! Une autre idée: je me demande si vous pouvez joindre les deux tables dans une vue, puis interroger la vue? – RickNZ

0

je suis tombé sur un problème similaire mais je fixe avec l'union il, quelque chose comme:

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