多个表上的 FreeText COUNT 查询超级慢

发布于 2024-08-13 03:39:48 字数 1557 浏览 5 评论 0 原文

我有两个表:

**Product**
ID
Name
SKU

**Brand**
ID
Name

产品表有大约 120K 条记录 品牌表有 30K 条记录,

我需要查找名称和品牌与特定关键字匹配的所有产品的数量。

我使用自由文本“包含”,如下所示:

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

此查询大约需要17秒。 我在运行此查询之前重建了 FreeText 索引。

如果我只检查 Product.Name。他们的查询时间不到 1 秒。同样,如果我只检查 Brand.Name。如果我使用 OR 条件,就会出现此问题。

如果我将查询切换为使用 LIKE:

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

需要1 秒。

我在 MSDN 上读到:http://msdn.microsoft.com/en-us/library/ms187787.aspx

要搜索多个表,请使用 将 FROM 子句中的表连接到 在结果集上搜索 两个或多个表的乘积。

所以我向 FROM 添加了一个 INNER JOINED 表:

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

这会导致错误: 无法对列“ProductName”使用 CONTAINS 或 FREETEXT 谓词,因为该列未建立全文索引。

所以问题是 - 为什么 OR 条件可能会导致查询速度慢?

I have two tables:

**Product**
ID
Name
SKU

**Brand**
ID
Name

Product table has about 120K records
Brand table has 30K records

I need to find count of all the products with name and brand matching a specific keyword.

I use freetext 'contains' like this:

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

This query takes about 17 secs.
I rebuilt the FreeText index before running this query.

If I only check for Product.Name. They query is less then 1 sec. Same, if I only check the Brand.Name. The issue occurs if I use OR condition.

If I switch query to use LIKE:

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

It takes 1 secs.

I read on MSDN that: 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.

So I added an INNER JOINED table to 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') 

This results in error:
Cannot use a CONTAINS or FREETEXT predicate on column 'ProductName' because it is not full-text indexed.

So the question is - why OR condition could be causing such as slow query?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

江心雾 2024-08-20 03:39:48

经过一番尝试后,我发现了一个似乎有效的解决方案。它涉及创建索引视图:

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

如果我运行以下查询:

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

现在再次需要1秒

After a bit of trial an error I found a solution that seems to work. It involves creating an indexed view:

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

If I run the following 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'))

It now takes 1 sec again.

用心笑 2024-08-20 03:39:48

我遇到了类似的问题,但我用 union 修复了它,例如:

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

I ran into a similar problem but i fixed it with union, something like:

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'))
很酷不放纵 2024-08-20 03:39:48

你有没有尝试过类似的事情:

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

Have you tried something like:

SELECT count(*) 
    FROM Product
    INNER JOIN Brand ON Product.BrandID = Brand.ID
    WHERE CONTAINS((Product.Name, Brand.Name), 'pants') 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文