编写SQL查询以搜索表中包含多列的术语的最佳和优化方法是什么?
例如,我有一个产品表:
id | title | color_id
-------------------
1 | Dress | 1 (red)
2 | T-shirt | 3 (blue)
3 | Pants | 2 (green)
4 | Socks | 1 (red)
5 | Dress | 2 (green)
6 | Shoes | 2 (green)
7 | Pants | 3 (blue)
还有一张颜色表:
id | color
----------
1 | Red
2 | Green
3 | Blue
如果用户输入红色连衣裙这个词,他必须看到身份Product
的{{1}},如果用户输入的话只是红色,因此他必须看到1
,其身份为Products
和1
。
更新:可能还有一些输入,例如4
或dress red
。
表的真实版本更复杂,但我试图以最简单的方式解释。
答案 0 :(得分:2)
只是“有效”的简单解决方案可能是:
SELECT *
FROM products
JOIN colors ON colors.id = products.color_id
WHERE
( title = "red" AND color = "dress" ) OR
( color = "red" AND title = "dress" )
如果优化器足够愚蠢而不能单独注意到它,这种情况可能会表现得更好:
WHERE
( title = "red" OR title = "dress") AND
( color = "red" OR color = "dress")
如果为问题添加更多属性(除了“标题”和“颜色”),如果存储不是问题,您可能希望将所有文本属性合并(和复制)到单个{{1 }列,并在此列上运行全文搜索。
VARCHAR
搜索变得非常简单:
CREATE TABLE products_properties (
product_id INT NOT NULL PRIMARY KEY,
properties VARCHAR (255),
FOREIGN KEY fk_product (product_id) REFERENCES products(id),
FULLTEXT ftx_properties (properties)
);
这在这个特定的例子中显然毫无意义,但是属性越多,它就越能加速查询。这种非规范化的代价是增加了维护SELECT products.*, colors.*
FROM products
JOIN colors ON colors.id = products.color_id
JOIN products_properties AS pp ON pp.product_id = products.id
WHERE MATCH(properties) AGAINST ("+red +dress")
表的复杂性。
如果你
,现在问题变得非常毛茸茸但看起来这不属于你问题的范围。
答案 1 :(得分:1)
如果我在SQL中执行此操作,我通常会在执行查询之前将查询分解为单个单词,然后根据有多少单词动态构建查询。
因此,对于您的示例,查询可能最终看起来像这样:
SELECT *
FROM products p
JOIN colors c ON c.id = p.color_id
WHERE
p.title LIKE '%red%' OR
c.color LIKE '%red%' OR
p.title LIKE '%dress%' OR
c.color LIKE '%dress%'
如果你有很多桌子,这可能会变得非常复杂。它也不是很有效,因为它不太可能使用任何索引。
更好的解决方案是使用像Lucene这样的专用文本索引产品(但这是一个完整的问题......)
答案 2 :(得分:1)
我的想法是使用这样的查询:
set @search = 'red dress';
SELECT *
FROM
products INNER JOIN colors
ON products.color_id = colors.id
WHERE
(FIND_IN_SET(title, REPLACE(@search, ' ', ','))>0)+
(FIND_IN_SET(color, REPLACE(@search, ' ', ','))>0) =
LENGTH(@search)-LENGTH(REPLACE(@search, ' ', ''))+1;
FIND_IN_SET中的两个替换用于创建用逗号分隔的属性列表:
red,dress
我正在检查此集合中是否title
。如果存在,则值为:
(FIND_IN_SET(title, REPLACE(@search, ' ', ','))>0)
否则,将被评估为1,0。同样适用于color
。
搜索字符串中的属性数量可以计算为:
LENGTH(@search)-LENGTH(REPLACE(@search, ' ', ''))+1
(是的,这是一个肮脏的把戏!)。如果匹配的属性数与@search字符串中的属性相同,则返回该行。请注意,表演会很差。
小提琴是here。