FREETEXT- COUNT Abfrage auf mehrere Tabellen ist super langsam
-
10-07-2019 - |
Frage
Ich habe zwei Tabellen:
**Product**
ID
Name
SKU
**Brand**
ID
Name
Produkt Tabelle hat über 120K Datensätze Marke Tabelle hat 30K Aufzeichnungen
Ich brauche Anzahl aller Produkte zu finden, mit Namen und die Marke ein bestimmtes Schlüsselwort entsprechen.
Ich benutze Freitext 'enthält' wie folgt aus:
SELECT count(*)
FROM Product
inner join Brand
on Product.BrandID = Brand.ID
WHERE (contains(Product.Name, 'pants')
or
contains(Brand.Name, 'pants'))
Diese Abfrage dauert etwa 17 Sek. Ich baute den Freetext-Index, bevor Sie diese Abfrage ausgeführt wird.
Wenn ich nur für Product.Name überprüfen. Sie Abfrage ist weniger als 1 Sekunde. Gleiche, wenn ich nur die Brand.Name überprüfen. Das Problem tritt auf, wenn ich verwende ODER-Bedingung.
Wenn ich wechseln Abfrage LIKE zu verwenden:
SELECT count(*)
FROM Product
inner join Brand
on Product.BrandID = Brand.ID
WHERE Product.Name LIKE '%pants%'
or
Brand.Name LIKE '%pants%'
Es dauert 1 Sek.
Ich lese auf MSDN, dass: http://msdn.microsoft.com /en-us/library/ms187787.aspx
Um auf mehrere Tabellen zu suchen, verwenden Sie ein verknüpfte Tabelle in Ihrer FROM-Klausel Suche auf einer Ergebnismenge, die das ist Produkt von zwei oder mehreren Tabellen.
So habe ich eine innere verbundene Tabelle 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')
Dies führt zu Fehler: Kann kein ENTHÄLT oder FREETEXT- Prädikat auf Spalte ‚Product‘ verwenden, weil es nicht volltextindiziert ist.
Die Frage ist also - warum ODER-Bedingung wie langsame Abfrage verursacht sein könnte
Lösung
Nach einem wenig Versuch ein Fehler fand ich eine Lösung, die zu funktionieren scheint. Es geht um eine indizierte Sicht zu erstellen:
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
Wenn ich die folgende Abfrage:
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'))
Es dauert jetzt 1 s wieder.
Andere Tipps
Haben Sie versucht, so etwas wie:
SELECT count(*)
FROM Product
INNER JOIN Brand ON Product.BrandID = Brand.ID
WHERE CONTAINS((Product.Name, Brand.Name), 'pants')
Ich lief in ein ähnliches Problem, aber ich regelte es mit Union, so etwas wie:
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'))