Domanda

Ho due tabelle:

**Product**
ID
Name
SKU

**Brand**
ID
Name

La tabella dei prodotti ha circa 120 KB di record La tabella dei marchi ha 30.000 record

Devo trovare il conteggio di tutti i prodotti con nome e marchio corrispondenti a una parola chiave specifica.

Uso il freetext 'contiene' in questo modo:

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

Questa query richiede circa 17 secondi. Ho ricostruito l'indice di FreeText prima di eseguire questa query.

Se controllo solo Product.Name. Interrogano meno di 1 secondo. Lo stesso, se controllo solo Brand.Name. Il problema si verifica se utilizzo la condizione OR.

Se cambio query per usare LIKE:

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

Ci vogliono 1 secondo.

Ho letto su MSDN che: http://msdn.microsoft.com /en-us/library/ms187787.aspx

  

Per cercare su più tabelle, utilizzare a   tabella unita nella clausola FROM a   cerca in un set di risultati che è il   prodotto di due o più tabelle.

Quindi ho aggiunto una tabella 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') 

Questo provoca un errore: Impossibile utilizzare un predicato CONTAINS o FREETEXT sulla colonna "ProductName" perché non è indicizzato full-text.

Quindi la domanda è: perché la condizione OR potrebbe causare una query lenta?

È stato utile?

Soluzione

Dopo un po 'di prova, ho trovato una soluzione che sembra funzionare. Implica la creazione di una vista indicizzata:

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 eseguo la seguente query:

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

Ora ci vogliono 1 secondo di nuovo.

Altri suggerimenti

Hai provato qualcosa del tipo:

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

Ho riscontrato un problema simile ma l'ho risolto con l'unione, qualcosa del tipo:

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'))
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top