两个 MySQL 表之间的最长前缀

Longest Prefix between two MySQL Tables

我有一个 MySQL 数据库有 2 tables:

Table答:

Table乙:

最初,我在 table A 中有大约 60,000 个条目,其位置列在开头为空。在 table B 中,我有大约 250,000 多个条目,其中包含大量区号、呼叫代码 (1, 011) 以及它们在世界上各自的位置。我想要的是用数字的位置填充 table A 的位置列的快速方法。

例如,如果 Table A 中的第一个条目是 (17324765600, null),我想读取槽 table B 并获取该数字的位置。现在我正在通过此查询获取号码的位置:

SELECT b.location
FROM 
  tableB b
  LEFT JOIN tableA a
     ON a.number LIKE CONCAT(b.calling_code, b.code, '%')
ORDER BY CHAR_LENGTH(b.code) DESC
LIMIT 1;

这给了我正确的位置(尽管我怀疑它会失败..)。问题是在性能方面这种方法是行不通的。如果我遍历所有 50k 数字

更新 1

请允许我将一些示例数据与预期输出放在一起: 样本 Table A:

number  location
17324765600 NULL
01134933638950  NULL
0114008203800   NULL
…60k Records + at the moment..

示例 Table B:

calling_code    code    location
1   7324765 US-NJ
011 34933   Spain
011 400820  China
…250,000+ records at the moment

处​​理后的预期输出: Table答:

number  location
17324765600 US-NJ
01134933638950  Spain
0114008203800   China

我想到的最好的是以下更新语句:

UPDATE tableA a JOIN tableB b ON a.location LIKE CONCAT(b.calling_code, b.code, '%') SET a.location = b.location

当然这里我不确定它是否总是 return 代码的最长前缀,例如如果在上面 tables 中有另一个以 73247XX 开头的代码让我们说代码适用于爱荷华州(仅作为示例)。我不确定查询是否总是 return 最长的代码,所以在这里我也需要帮助。

如果样本有帮助,请告诉我。

.SQL 为数据库结构: Download

更新 2:

我正在考虑按以下方式执行此操作:

在 table A 中插入数据之前,我正在考虑将 Table B 导出到 CSV 中并按区号对其进行排序,这样我就可以有 2 个指针,一个用于条目数组table A 和一个用于 csv,都按区号排序,这样我就可以进行一种并行搜索并在 PHP 上填充条目的位置,而不必在 MySQL 中执行此操作.

让我知道这种方法是否是更好的选择,如果是的话,我会对其进行测试并发布答案。

如果您想要所有位置,则需要删除 LIMIT

SELECT b.location
FROM 
  tableB b
  LEFT JOIN tableA a
     ON a.number LIKE CONCAT(b.calling_code, b.code, '%')
ORDER BY CHAR_LENGTH(b.code);

如果你想要相同的位置名称不应该出现两次那么你需要使用GROUP BY

SELECT b.location
FROM 
  tableB b
  LEFT JOIN tableA a
     ON a.number LIKE CONCAT(b.calling_code, b.code, '%')
GROUP BY b.location  ORDER BY CHAR_LENGTH(b.code) ;

你一个join只有250000条记录,压力不大。您应该为搜索列和 fine tune your mysql server 建立适当的索引。设置一个good indexing & server variables well即可轻松解决您的问题。优化您的查询 well.Generally 当我们有很多连接和很多字符串比较时它会产生问题。

我想你需要这样的查询-

UPDATE a SET a.location = ( 
                            SELECT location from b 
                            WHERE a.number LIKE CONCAT(b.calling_code, b.area_code, '%') 
                            ORDER BY LENGTH(CONCAT(b.calling_code, b.area_code, '%')) desc 
                            limit 1
                          );

由于没有收到任何明确的回复,我决定采用以下方法:

在此过程之前,我准备了 2 个新的 table,一个用于国家代码的 table 和一个用于州代码的 table(因为我还需要知道州以防万一该号码在美国境内)。两个 table 都会有:国家、州、calling_code、代码……

至于这 2 个 table,我用前缀分解了所有号码,并按区号将它们分组,因此我没有用完整的 6 个号码来识别 country/state,而是按前 3 个数字以及代码是否在美国境内,因此 2 tables.

通过这些修改,我能够将 250,000 多行 table 拆分为大约 300 行(每行 table)。

之后我将按照以下步骤操作:

  1. 我得到 phone 个号码的列表
  2. 我首先执行一个与我发布的查询非常相似的查询,以更新属于 country_code table
  3. 的所有号码
  4. 然后我更新仍然没有分配位置的行 state_code
  5. table
  6. 我必须设置某种 cron 才能每隔 x 时间完成一次,以避免出现大量 phones。

这可能不是最好的方法,但对于我目前能够使用的 50k 个数字(手动执行查询并进行更多优化)将其缩短到大约 10 秒,每隔x 时间(这将允许对少于 10k 个数字执行此过程)将使这一过程顺利进行。

我会将此标记为答案,但如果其他人奇迹般地想出更好的答案,我会确保更新此答案。

分而治之!