使用大型地址数据库进行自动建议的最佳方法是什么?

问题描述

我有一个包含一个国家大约 300,000,000 个地址的数据库。此数据应该用于表单中的自动建议,即:如果地址是 1900 Country Hill Road用户将键入 Count(假设至少 3 个字符来触发自动建议是个好主意) ,并且该表单可能会向用户提供前 10 个结果,即:

165 Countable Road
1890 Countable Road
44 Counting Circle
900 Country Drive
13 Country Hill Road
1900 Country Hill Road
344 Country Mountain Place
etc.

选择地址还要填写城市和邮政编码。 注意:这是在地址格式为 Street ##/## 的国家/地区,因此实际名称是第一个输入的内容

执行一次 SELECT * FROM addresses WHERE street LIKE 'Count%' LIMIT 10 查询平均需要大约 3 秒。仅选择 street,house_number,city,zip 会稍微快一些。每行有 19 列。我已经根据一些 MysqL 指南在其中一列上添加了索引,但这并没有显着帮助。我希望每个请求的时间低于 500 毫秒。

解决此问题的最佳方法是什么?想到的事情是:

  • 根据街道的首字母将数据库表分成多个表,并根据用户键入的内容选择表。这意味着我最终会得到大约 26 张桌子。
  • 将所有内容转换为多个 JSON 文件
  • 进一步研究优化数据库

解决方法

让我逐步完成分析。

  1. 您正在搜索给定字符串开头的街道地址,对吗?
  2. WHERE street LIKE 'Count%'INDEX(street) 一起是合理的最佳选择。没有单独的表,没有 JSON,没有首字母等。
  3. LIMIT 10 将有效地找到前 10 个这样的项目。注意:添加 ORDER BY 可能会影响性能。
  4. SELECT street 在索引的 B+Tree 中查找结果。因为这就是你所需要的,所以使用它。 SELECT <<some columns>>SELECT * 必须执行额外操作才能获取其他列。

这样的索引会向下钻取 B+Tree 到“Count...”的第一次出现,然后从那里向前扫描。即使数据集无法缓存在 RAM 中,实际上也只有一次磁盘命中,这需要几毫秒。如果您需要额外的列,那么额外的操作可能需要多 10 次磁盘命中(由于 LIMIT 10)。

因此,重要的是 INDEX 包含完全您需要接收自动建议的内容。

ORDER BY 只有在你说ORDER BY street(或ORDER BY street DESC)时才可以。否则,它必须找到以“count”开头的数千(百万?)条街道,对这个列表进行排序,然后交付 10 条。

根据该分析,“最少 3 个字符”并不重要。但是,我的 UI 直觉是 3 是合理的。

哦,还有一个问题。由于可能在数千个城镇中都有“1 Main St”,因此“Main”的自动选择很可能会显示相同“1 Main St”的 10 个副本。

哦,我没有处理你从你的例子中暗示的东西。 street 包括街道号码。或者,您可能有两列 - street_name(用于搜索)和 street_number。所以...

有两列:

  • 一个用于自动建议(“Main St”)
  • 一个用于展示(“1 Main St,Acron OH”)

然后有INDEX(auto_suggest,display)。这将为您提供获得自动建议值的最小工作效率,但允许同样有效地显示完整地址。

但这仍然存在重复地址的问题。好的,我现在不得不推荐一张额外的桌子。它将包含所有唯一街道名称,没有 street_number 等。

CREATE TABLE AutoSuggest (
    street VARCHAR(99) NOT NULL,PRIMARY KEY(street)
) ENGINE=InnoDB;

请注意,在 MySQL 中,PRIMARY KEY 是与数据聚集的 B+Tree 索引,并且是 UNIQUE。对于 200M 地址,此表可能大约为 1GB,在补偿了 dups、开销等之后。在您的应用程序运行一段时间后,大部分表将缓存在 buffer_pool 中。这使得典型的自动建议查找时间约为 1 毫秒。

但是,这只会给您街道名称,而不是地址等。也许您需要名为 full_street 的第二列(并更改为 PRIMARY KEY(street,full_street)):

INSERT INTO AutoSuggest (street,full_street)
    VALUES
    ("Main St","1 Main St");

这提供了前面提到的大部分好处和一些缺点。

用你的两个目标之间的权衡来思考我的评论:

  • 快速自动建议;
  • 自动建议期间 UI 呈现的内容。