我正在为应用构建数据库,我正在测试更大的数据集上的性能问题。我生成了大约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%')
答案 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%`
强制进行全表扫描。要解决这个问题,通常需要了解相关领域和应用程序的一些知识
简单的方法是只搜索'开头'。其他包括全文搜索,基于功能的索引,具有“分组表”,用于预先排序并列出已知搜索的相关记录。