搜索与外卡的多对多关系,性能问题

时间:2013-05-04 18:56:39

标签: mysql sql scalability

我正在为应用构建数据库,我正在测试更大的数据集上的性能问题。我生成了大约250,000个位置记录。可以将每个位置分配给许多类别,并且可以将类别分配给许多位置。我的数据集为每个位置分配了2-4个类别。

我想允许用户通过过滤使用通配符搜索允许哪些类别来搜索位置。所以也许我希望将所有类别与“红色”一词相匹配。因此,如果我输入红色,现在它会显示所有具有“红色”类别标题的位置。另外,我想使用相同的字符串通配符搜索位置标题。

我写了一个工作的查询,但在大型数据集中性能很糟糕。基本上我正在使用内部查询,如果设置了我的限制并且我快速找到结果(大约.05ms)就可以了。如果我没有立即找到任何结果,它看起来像是通过整个数据库,查询大约需要9-10秒。

以下是我的数据库的简化布局:

locations: id | title | address
categories: id | title
locations_categories: id | location_id | category_id

以下是我目前使用的查询:

SELECT `id`,`title`,`address`
FROM (`locations`)
WHERE title LIKE '%string%'
AND WHERE id IN (
 SELECT location_id 
 FROM locations_categories 
 JOIN categories ON categories.id = locations_categories.category_id 
 WHERE categories.title LIKE '%string%')

2 个答案:

答案 0 :(得分:1)

首先,您的主查询只使用子查询的值,因此可以重写:

 SELECT location_id 
 FROM locations_categories 
 JOIN categories ON categories.id = locations_categories.category_id 
 WHERE categories.title LIKE '%string%'

但我建议将此查询拆分为两个JOIN,对于大数据集来说速度很慢。第一个将获得必要的类别ID(带分页):

SELECT id
FROM categories
WHERE title LIKE '%string%' LIMIT BY <start>, <step>

然后你可以获得locations_categories:

SELECT location_id FROM locations_categories WHERE category_id IN (...)

您将使用您获得的位置ID来检索相应的记录:

SELECT * FROM locations WHERE id IN (...)

这3个查询的组合将比原始查询快得多。

此外,请确保您的标题列已编入索引 - 它可能是瓶颈。但由于您在搜索字词的开头有通配符,因此您必须在此处使用FULLTEXT索引。

答案 1 :(得分:1)

您的解释计划将确认(或反驳)此但我怀疑您的问题是条款中的前导%

WHERE categories.title LIKE '%string%' 

WHERE title LIKE '%string%`

强制进行全表扫描。要解决这个问题,通常需要了解相关领域和应用程序的一些知识

简单的方法是只搜索'开头'。其他包括全文搜索,基于功能的索引,具有“分组表”,用于预先排序并列出已知搜索的相关记录。