![]() |
Задавайте вопросы, мы ответим
Вы не зашли.
Добрый день!
Некогда давно создавалась база для хранения некой информации, в том числе и номеров телефонов.
Формат хранение следующий:
1. Таблица стран с полями id, name, phone_code
2. Таблица данных, где телефоны хранятся в следующем виде country_id(int), phone_code(int), phone_number(int).
Таблица данных порядка ~200000 записей, и используется активно, в том числе добавление и удаление записей.
В данный момент столкнулись с проблемой, что номера телефонов начинаются с нуля, и при добавлении в базу эти нули "съедаются", в результате записывается и отображается при выводе неправильный номер.
Как вариант, для лечения данной проблемы, можно поле для кода и номера изменить на char или varchar, но есть проблема.
При добавлении записи в таблицу идёт проверка сколько записей с данным телефонным номером существует, и если поля будут типа char или varchar, то такие запросы оказываются тяжелее по сравнению с полями типа int.
Подскажите, как можно решить проблему "съедания" нулей, без проседания производительности при поиске ?
Неактивен
Если длинна номера телефона фиксирована, то проще при отображении дописывать нужное кол-во нулей.
Неактивен
Вариант с zerofill не подойдёт, длина номера не фиксированная.
Неактивен
Тогда или varchar (но это большие расходы на индекс), или втрое поле,в котором хранить длину номера, а при выводе отображать нужное кол-во нулей.
Неактивен
vasya написал:
Тогда или varchar (но это большие расходы на индекс), или втрое поле,в котором хранить длину номера, а при выводе отображать нужное кол-во нулей.
добавлять новое поле тоже не очень приемлимый вариант, потому что нужно будет дорабатывать софт под такое поле, ну и ещё нужно тестировать, не будет ли это более ресурсоемко добавление ещё одного поля в where, чем перевести поля код и номер в varchar. Разве что, если только найти в mysql или самому написать функцию, которая в однозначном порядке будет конвертировать весь телефонный номер в число и использовать это поле для поиска, что-то вроде функций ATON и NTOA для ip-адресов.
С индексом этих полей тоже немного непонятно, проводил тестирование на таблице в которой больше миллиона записей, таблица с разными данными и в ней поля как писал выше country_id, phone_code, phone_number.
Поля phone_code и phone_number делаю varchar, пробую делать индекс из трёх полей country_id, phone_code и phone_number, и три отдельных индекса по каждому полю, и делаю запрос:
SELECT COUNT(*) FROM table WHERE country_id = 'x' && concat(phone_code,phone_number) = 'zzzyyyyyyy'
В таком запросе mysql отказывается использовать данные индексы. Может есть ещё вариант как сделать индексы чтоб поиск шёл по индексам, а не по всей таблице?
И ещё небольшой вопрос, если под поля phone_code и phone_number предусмотреть размер не более 6 и 8 символов соответственно, теоритически, должен ли быть выйгрыш при поиске если сделать данные поля char(6) и char(8) вместо varchar(6) и varchar(8) ?
На своей тестовой базе пробовал так и так, разницы не заметно.
Неактивен
_Igor_ написал:
С индексом этих полей тоже немного непонятно, проводил тестирование на таблице в которой больше миллиона записей, таблица с разными данными и в ней поля как писал выше country_id, phone_code, phone_number.
Поля phone_code и phone_number делаю varchar, пробую делать индекс из трёх полей country_id, phone_code и phone_number, и три отдельных индекса по каждому полю, и делаю запрос:
SELECT COUNT(*) FROM table WHERE country_id = 'x' && concat(phone_code,phone_number) = 'zzzyyyyyyy'
В таком запросе mysql отказывается использовать данные индексы. Может есть ещё вариант как сделать индексы чтоб поиск шёл по индексам, а не по всей таблице?
Bндекс не будет использоваться, если в части where поле входит в состав какого-нибудь выражения.
В вашем случае нужно убрать concat:
SELECT COUNT(*) FROM table WHERE country_id = 'x' && phone_code = 'zzz' && phone_number = 'yyyyyyy'; -- тогда составной индекс будет использоваться.
_Igor_ написал:
И ещё небольшой вопрос, если под поля phone_code и phone_number предусмотреть размер не более 6 и 8 символов соответственно, теоритически, должен ли быть выйгрыш при поиске если сделать данные поля char(6) и char(8) вместо varchar(6) и varchar(8) ?
А за счет чего вы ожидаете прибавку?
Неактивен
vasya написал:
Bндекс не будет использоваться, если в части where поле входит в состав какого-нибудь выражения.
В вашем случае нужно убрать concat:
SELECT COUNT(*) FROM table WHERE country_id = 'x' && phone_code = 'zzz' && phone_number = 'yyyyyyy'; -- тогда составной индекс будет использоваться.
спасибо за подсказку, такого ньюанса не знал.
vasya написал:
А за счет чего вы ожидаете прибавку?
Была мысль, что если сделать поле varchar, то в данном случае размер памяти для хранения данных будет меньшим, ну и поиск будет работать быстрее. Как показали мои результаты тестов на базе с ~1 млн. записей, никакой прибавки не наблюдалось, скорости выполнения запросов были одинаковы.
P.S. Может кому будет полезно, изначальная проблема была решена следующим образом. Поле кода и номера телефона сделано типом varchar(6) и varchar(8), а для поиска было создано поле bigint, в которое записывается код и номер (в международном формате записи телефонный код не может начинаться с 0, поэтому тип bigint вполне подходит). Создан индекс из двух полей country_id и нового поля типа bigint (название поля phone_search).
Для поиска используется запрос: SELECT COUNT(*) FROM table WHERE country_id = 'x' && phone_search = 'zzzyyyyyyy';
С использованием индексов всё просто летает, быстрее даже чем было до этого.
Неактивен