Потратил час на спор с клиентом, что 1С работает медленнее, чем его база на Oracle, поэтому, обеспечить одновременную, безглючную работу нескольких операторов, чтобы они, вводя номер телефона, по первым цифрам получали в выпадающем списке подходящие номера, нельзя… Все бы ничего, но
1. номеров может быть много… десятки тысяч… сеть пиццерий в Санкт-Петербурге, как ни как
2. мое неумение решить эту проблему грозило срывом хорошего договора
В конечном итоге, убедили клиента, что, хотя это и сложно, но проблему решим. Договор заключили. А вечером действительно решили вопрос 🙂
Всего-то нужно было — посмотреть на вопрос не глазами клиента а нашими, т.е., программистов. Чем грузится база? Запросами к ней и блокировками таблиц. Значит, нужно большую часть работы повесить не на сервер, а на клиентское приложение!
И так, простой метод:
1. по первой цифре отбираем в запросе нужные нам номера
2. все последующие цифры — это запрос не к базе, а к списку уже отобранных нами номеров
Осталось немного «косметики». Проблема: пока вводятся цифры в поле ввода, никакая обработка ожидания не срабатывает. Как быть? Тот франч, что был до нас и потерял этот заказ, не предложил решения.
Но нечего баловать операторов полями ввода и выпадающими списками, дадим им нечто лучшее, отдельную форму ввода. Мотивация — теперь появилась возможность работать с сенсорными экранами…
— У Вас нет сенсорных экранов? Но ведь будут однажды!
— Да, конечно когда-нибудь будут…
Как я люблю это наше «надо прозапас»! И приятно, что наша небольшая супер команда оказалась хитрее крупного франча с филиалами во многих городах… 🙂
В общем, просто делюсь хорошим настроением и небольшой фичей, которую, если у кого похожая задача возникнет, не придется делать самому. В прилагаемой базе сгенерировано 50 тыс. номеров. Проверьте скорость работы. Можно и в сети.
«Ну а как быть, если номеров несколько миллионов?» — спросит кто-то
Не страшно! (Наверное)
Вариантов вижу 2, по крайней мере.
1. Использовать дополнительные поля в справочнике телефонов для отбора с включенной сортировкой. В частности: «Первый символ», «Два первых символа», «Три первых символа». Наверное, стоит все-таки обращаться к базе, пока длина введенной части не более 3-х символов, а вот потом уже работать со сформированным списком. Но по поводу этого готов услышать «за» и «против»
2. Использовать локальную базу номеров, выгруженную в виде того же dbf, и обращаться к ней на клиентской машине. При этом, dbf-ок можно иметь несколько. Опять же, по первому (двум) символу в номере.
Плюс за оригинальное решение проблемы поля ввода 🙂
Собственно по алгоритму поиска — мне кажется, не стоит искать сразу после первой цифры. Вероятность, что при этом будет найден именно нужный телефон ничтожна, а нагрузку на базу это создаст немаленькую.
Разве что это требование заказчика.
Но и тогда лучше сделать типа ВЫБРАТЬ ПЕРВЫЕ 100.
Думаю что поле ввода можно было реализовать с клавиатуры… отдельно ввод, отдельно форма с вариантами… Ну и да я согласен с (1)номеров менее 4ех чисел ну хотя-бы 3ех… можно сделать.
А что не так с полем ввода? При наборе символов в поле ввода при малейшей задержке возникает событие «Автоподбор текста». Еще бы посоветовал навесить индекс на поле «номер телефона» в БД. Правда, в вашем решении он бесполезен, так как по одной цифре БД его точно не будет использовать.
Тоже не вижу проблемы — есть автоподбор текста, есть менеджер временных таблиц для запросов, есть индексирование. Подобную задачу помню решал еще на 8.1 лет 5 назад и база номеров тоже была огромной (около 100 000) — все решилось за 3-4 часа без взрыва мозга. А там помимо выборки стояла еще и реальная проблема — формат номеров, коих было великое множество.
Вы извините, но когда я вижу подобные «проблемы» — я начинаю понимать, почему у заказчиков такое предвзятое отношение к 1С, франчам и большинству специалистов 1С.
(3) Ну, при использовании этого метода, конечно, будет все сложнее, но не намного. По крайней мере, нужно сравнивать ту строку, что сейчас в поле ввода с той, что в последний раз была отработана. Т.е., пара лишних переменных…
(4) А что там 3-4 часа было делать?
Проблемы, на самом деле, есть.
Вот вопросы, которые я задаю себе, думая об этой задаче, и которые, я уверен, задаст заказчик впоследствии:
1. Номера бывают городские и мобильные, как сократить ввод мобильного номера? Цифра «8», по сути, загонит все мобильные в мой список.
2. И опять же, номер оператор… 8987 — это МТС у нас в городе. Несколько сот тысяч абонентов подключено на номер, начинающийся с этих цифр. Тут я соглашаюсь с (1): нужно подумать, как это оптимизировать.
3. А что если номеров будет не 50, а 500 тыс? И заказчик уже на это намекал. Реально ведь, чтобы 500 тыс. питерцев заказали пиццу!
Т.е., решение задачи требует оптимизации. И тут без выноса мозга, похоже, не обойтись.
На самом деле, заказчик сформулировал задачу достаточно однозначно: общая база 1С (не управляемые формы), эмуляция локальной сети через интернет подключение, несколько десятков операторов. Телефонных номеров — много (весь С-П). Нужно чтобы все операторы могли работать одновременно, без каких-либо тормозов.
(6) можно посоветовать префиксные цифры для сотовых хранить в отдельном столбце. Там где делаю заказы обычно, «8»-ку для сотовых номеров не нужно указывать: логичная оптимизация :). При показе пользователю «склеивать» префикс и его номер. При поиске же префикс может послужить дополнительным фильтром для найденных номеров: но поиск по нему бы не запускался. Но если в базе уже много номеров, может быть рутинным решение выглядеть по внедрению этой оптимизации 🙂
(6)О какой оптимизации идет речь? Пара лишних переменных в случае такой «тяжелой» задачи — думаю не проблема. Оптимизация здесь может быть только в том, чтобы:
1) все номера хранить и вводить без восьмерки
2) добавить измерения с индексацией по первым 3 и 3-6 символам номера
Для выборки использовать автоподбор по первым 3, далее 6 символам (благо количество введенных символов можно узнать без проблем) использую запрос с ВТ и индексами (и менеджером, чтобы по 100 раз в базу не лазить).
Все!!! Какая еще здесь может быть оптимизация? Есть желание — навешайте триггеров в postgre (oracle), потрясите планы запросов (хотя тут запрос линейный). Мы всегда ограничены платформой — не стоит об этом забывать!
Проблема: пока вводятся цифры в поле ввода, никакая обработка ожидания не срабатывает.
Для того что бы система дала обработать изменение после ввода любово символа (1-го, 2-го и т.д.) можно использовать элемент ActiveX к примеру MS Forms 2.0 TexBox. При каждом вводе символа будет отрабатывать событие ПриИзменении().
При наборе цифр сколько номеров телефонов должно быть в отобранном списке? Разумное значение какое?
Мне кажется нет смысла «отображать» более нескольких десятков номеров. В этом случае можно завести отдельную таблицу (регистр) со значениями первых уникальных n-цифр (где n>3…5) номеров при условии, что таких номеров больше некого порога (например, 100). Сначала поиск осуществлять по ней, а как только значений не будет найдено можно лезть в общую таблицу, где записей с первыми n-цифр будет меньше порога.
Телефоны — в текстовый файл. Регулярные выражения. Отработает за < 1 сек.
Но оперативной памяти на локальной машине должно быть достаточно — весь текст в памяти.
У меня 1С сыпалась при 2 000 000 строк на 2Гб оперативки на 32бит WinXP
Если на БД — то вынести телефоны на SQL базу, работающую в ОЗУ.. MySQL, например. И организовать доступ к данным через web-сервис к этой базе из 1С. И, опять же, в запросе использовать регулярные выражения, что позволит искать данные в любой части номера..
Если делать на 1С — можно попробовать иерархический справочник (иерархия элементов), 3 уровня.
1й уровень — код страны, 2й — код города/оператора, 3й — телефон..
Выборка на одно уровне иерархии происходит быстрее.
В крайнем случае — создать у регистра, где хранят номера, индексированное поле, куда писать нормализованные номера — только циферки, без лишних пробелов, черточек, тире.. И запрос с инструкцией ПОДОБНО:
ВЫбРАТЬ Номер Из Регистр ГДЕ Номер ПОДОБНО %ном% ИЛИ Номер ПОДОБНО %ном ИЛИ Номер ПОДОБНО ном%»
И что, если просто проиндексировать поле Телефон и включить управляемые блокировки, то работает медленно? Там второй Пентиум на сервере?
Неплохо бы предусмотреть поиск по подстроке.
Набрал, к примеру, 888, а в списке:
+79128882931
+79878470888
Для этого надо создать несколько индексных таблиц для отбора номеров по подстроке из 3,4,5 символов.
При добавлении номера в базу — прописывать его и в индексные таблицы, со всеми возможными подстроками поиска.
P.S. Пора уже с call-центром соединять.. 😉