1

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

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

我写了一个有效的查询,但在大型数据集中性能很糟糕。本质上,我使用的是内部查询,如果设置了限制并且我可以快速找到结果(大约 0.05 毫秒),这很好。如果我没有立即找到任何结果,看起来它会遍历整个数据库并且查询大约需要 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%')
4

2 回答 2

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此处使用索引。

于 2013-05-04T19:21:07.543 回答
1

您的解释计划将确认(或反驳)这一点,但我怀疑您的问题是条款中的领先 %

WHERE categories.title LIKE '%string%' 

WHERE title LIKE '%string%`

强制全表扫描。为了解决这个问题,通常需要对相关领域和应用程序有一些了解

简单的方法是只搜索“开始于”。其他包括全文搜索、基于函数的索引、具有预先排序和列出已知搜索的相关记录的“分组表”。

于 2013-05-04T22:01:08.333 回答