Как сопоставить префикс номера телефона с номером телефона из SQL - PullRequest
3 голосов
/ 21 марта 2020

Я пытаюсь извлечь префикс кода страны из списка номеров и сопоставить их с регионом, к которому они принадлежат. Данные могут выглядеть примерно так:

| id | phone_number   |
|----|----------------|
| 1  | +27000000000   |
| 2  | +16840000000   |
| 3  | +10000000000   |
| 4  | +27000000000   |

Коды здесь:

  • Американское Самоа: + 1684
  • США и Карибский бассейн: +1
  • Южная Африка: + 27

И желаемый результат будет примерно таким:

| country                     | count |
|-----------------------------|-------|
| South Africa                | 2     |
| American Samoa              | 1     |
| United States and Caribbean | 1     |

Есть некоторые трудности, потому что

  • коды префиксов стран варьируются от 1 до 4 номеров, и даже без префикса страны
  • длина номера телефона варьируется от места к месту.
  • У меня нет доступа на запись в эту БД, поэтому добавление еще одного столбца, хотя, вероятно, является лучшим решением, не будет работать в этом случае использования

Это мое текущее решение:

SELECT 
CASE
    WHEN SUBSTRING(phone_number,1,5) = '+1684' THEN 'American Samoa'
    WHEN SUBSTRING(phone_number,1,5) = '+1264' THEN 'Anguilla'
    ...
    WHEN SUBSTRING(phone_number,1,5) = '+1599' THEN 'Saint Martin'
    WHEN SUBSTRING(phone_number,1,4) = '+355' THEN 'Albania'
    WHEN SUBSTRING(phone_number,1,4) = '+213' THEN 'Algeria'
    ...
    WHEN SUBSTRING(phone_number,1,4) = '+263' THEN 'Zimbabwe'
    WHEN SUBSTRING(phone_number,1,3) = '+93' THEN 'Afghanistan'
    WHEN SUBSTRING(phone_number,1,3) = '+54' THEN 'Argentina'
    ...
    WHEN SUBSTRING(phone_number,1,3) = '+58' THEN 'Venezuela'
    WHEN SUBSTRING(phone_number,1,3) = '+84' THEN 'Vietnam'
    WHEN SUBSTRING(phone_number,1,2) = '+1' THEN 'United States and Caribbean'
    WHEN SUBSTRING(phone_number,1,2) = '+7' THEN 'Kazakhstan, Russia'
    ELSE 'unknown'
END as country_name,
count(*)
FROM users
GROUP BY country_name
order by count desc

Существует ~ 205 WHEN ... THEN случаев. Кажется, это очень неэффективно и время ожидания. Я предполагаю, что это потому, что он запускает сопоставление с образцом в каждой строке. Для этого потребуется масштабировать до примерно 10 с миллионов строк

Есть ли более эффективный способ сделать это?

Я использую postgreSQL 9.6.16

1 Ответ

1 голос
/ 21 марта 2020

Несмотря на чтение всей таблицы, здесь может помочь индекс. Для агрегирования данных по коду страны СУБД должна отсортировать все строки по коду страны. Сортировка - дорогостоящая операция, особенно для больших массивов данных. Если бы у вас был индекс по кодам стран, СУБД нашла бы коды, уже предварительно отсортированные в индексе, и могла бы избежать работы по сортировке данных.

У вас нет отдельного кода страны в столбец, но каждый номер телефона начинается с кода, чтобы вы могли индексировать полный номер телефона:

create index idx on users (phone_number);

Затем вы должны четко заявить СУБД, что вас интересует начало строки, поэтому он рассмотрит использование индекса. Вызов функции типа SUBSTRING на номер телефона может сделать СУБД слепой к этому. Вместо этого используйте LIKE. Согласно документам (https://www.postgresql.org/docs/9.3/indexes-types.html), индексы для строк можно использовать с LIKE 'something%':

WHEN phone_number LIKE '+1684%' THEN 'American Samoa'

Нет гарантии, что это поможет, но стоит попробовать считать. Это зависит от того, видит ли оптимизатор преимущество использования предварительно отсортированных телефонных номеров из индекса.

...