Выбор самой длинной подстроки

pavelsh_chel

Есть первая таблица:prefix price7 107351 573512 2Есть вторая таблицаtime destination10:20:01 74951231231210:20:01 73517547443510:20:01 735128685664В принципе обычная задача, на основании телефонного префикса сделать назначение цены для звонков:то есть хочется итоговую вот такую таблицу:time destination price10:20:01 749512312312 10 10:20:01 735175474435 510:20:01 735128685664 2Проблема в том, что префиксы параллельной длины. Даже и не знаю как поступить.Не хватает вложенных запросов в mysql 4.0
24 ответа

pavelsh_chel

префиксы параллельной длины.
э?


pavelsh_chel

Префиксы переменной длины


pavelsh_chel

я так придумал:
SELECT c.calltime, c.destination,
IFNULL(p5.price, IFNULL(p4.price, IFNULL(p3.price, IFNULL(p2.price, IFNULL(p1.price, 'prefix not found'))))) AS price
FROM calls c
LEFT JOIN prices p1 ON p1.prefix=LEFT(c.destination, <b>1</b>)
LEFT JOIN prices p2 ON p2.prefix=LEFT(c.destination, <b>2</b>)
LEFT JOIN prices p3 ON p3.prefix=LEFT(c.destination, <b>3</b>)
LEFT JOIN prices p4 ON p4.prefix=LEFT(c.destination, <b>4</b>)
LEFT JOIN prices p5 ON p5.prefix=LEFT(c.destination, <b>5</b>)
количество p1..p5 увеличить до максимальной длины префиксов


pavelsh_chel

я так придумал:
SELECT c.calltime, c.destination,
IFNULL(p5.price, IFNULL(p4.price, IFNULL(p3.price, IFNULL(p2.price, IFNULL(p1.price, 'prefix not found'))))) AS price
FROM calls c
LEFT JOIN prices p1 ON p1.prefix=LEFT(c.destination, <b>1</b>)
LEFT JOIN prices p2 ON p2.prefix=LEFT(c.destination, <b>2</b>)
LEFT JOIN prices p3 ON p3.prefix=LEFT(c.destination, <b>3</b>)
LEFT JOIN prices p4 ON p4.prefix=LEFT(c.destination, <b>4</b>)
LEFT JOIN prices p5 ON p5.prefix=LEFT(c.destination, <b>5</b>)
количество p1..p5 увеличить до максимальной длины префиксов
Убить тебя за это мало...Есть гораздо более интересные решения... Приводились и на MySQL ветке форума в том числе...


pavelsh_chel

Есть гораздо более интересные решения... Приводились и на MySQL ветке форума в том числе...
Где бы их найти, эти интересные решения.У меня вот тоже получилось нечто похожее. Но неработающее
SELECT H.DEST, H.TARIF, H.PRICE, H.SES_TIME, R.PRICE
FROM RATES R, DEST_CODE D, HOT_STAT H
WHERE D.DEST_ID=R.CODE_ID
	AND D.CODE IN (
 SUBSTRING(H.DEST,<b>1</b>,<b>20</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>19</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>18</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>17</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>16</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>15</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>14</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>13</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>12</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>11</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>10</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>9</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>8</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>7</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>6</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>5</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>4</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>3</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>2</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>1</b>))
 AND R.RATE_ID='92'
 AND SES_TIME<><b>0</b>
Структура таблиц здесь немного сложнее, чем в моем примере, но суть та же.


pavelsh_chel

Где бы их найти, эти интересные решения.
раз два


pavelsh_chel

В обоих версиях используются подзапросы. Я тоже через использование подзапросов эту задачу бы решил самостоятельно!Но! У меня MySQL 4.0.x. И через него, к сожалению, подзапросы не запускаются. Версию сервера сменить не могу. Увы. Она идет в комплекте с программным решением.Как без использования подзапросов сделать выборку?У меня вышеприведенный запрос расчитан на следующую структуру базы:Таблица DEST_CODE это пары видаDEST_ID - CODE, где DEST_ID - идентификатор строчки, CODE - префикс направления (уникальный код города например);Таблица RATESCODE_ID PRICE RATE_IDТаблица, где определяется для префикса направления с идентификатором CODE_ID, цена PRICE для тарифного плана с идентификатором RATE_ID. Таблица HOT_STAT, фактически CDR, то есть таблица записей о звонках:DEST SES_TIMEгде DEST - набранный телефонный номер, SES_TIME - время сессии.Вот мой запрос, который возвращает двойные записи в том случае, если в таблице DEST_CODE выбираются два более префиксов (то есть для Москвы 7, 7495)
SELECT H.DEST, H.SES_TIME, R.PRICE
FROM RATES R, DEST_CODE D, HOT_STAT H
WHERE D.DEST_ID=R.CODE_ID
	AND D.CODE IN (
 SUBSTRING(H.DEST,<b>1</b>,<b>20</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>19</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>18</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>17</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>16</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>15</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>14</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>13</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>12</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>11</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>10</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>9</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>8</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>7</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>6</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>5</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>4</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>3</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>2</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>1</b>))
 AND R.RATE_ID='92'
 AND SES_TIME<><b>0</b>


pavelsh_chel

Убить тебя за это мало...Есть гораздо более интересные решения... Приводились и на MySQL ветке форума в том числе...
в задаче говорилось, что запрос должен работать в MySQL 4.0, там даже подзапросов нед


pavelsh_chel

в задаче говорилось, что запрос должен работать в MySQL 4.0, там даже подзапросов нед
Я это прекрасно понимаю - не тупой, и исходные вопросы от авторов читать внимательно умею. И тем не менее - однопроходные решения поставленной задачи приводились, и не раз. Если что, то поищи по ключевому слову "хулиганский".Найдется как минимум пара топиков даже в пределах MySQL-ой ветки форума. Там задача не совсем та, что автор решает, но предложенное решение очень неплохо ложится на условия и этой задачи тоже...


pavelsh_chel

Ничего себе там вариантики. Просто так не разберешься. :)И даже с наскока не поймешь как они пересекаются с моей задачей.Буду ковыряться


pavelsh_chel

Ничего себе там вариантики. Просто так не разберешься. :)И даже с наскока не поймешь как они пересекаются с моей задачей.Буду ковыряться
Ты это про какие именно? Если есть какие-то вопросы, спрашивай.З.Ы."Спросить - стыд нескольких минут, не знать - стыд всей жизни!"(с)


pavelsh_chel

Прочитал все, что мог найти. К сожалению у меня не Oracle. Была бы хранимая процедурка. Эх. Или хотя бы вложенные запросы, я бы сам справился. А так у меня пока не получается.Может я какое то рациональное зерно для своего случая не вижу?Потому как все варианты идут через вложенный запрос


pavelsh_chel

Прочитал все, что мог найти. К сожалению у меня не Oracle. Была бы хранимая процедурка. Эх. Или хотя бы вложенные запросы, я бы сам справился. А так у меня пока не получается.Может я какое то рациональное зерно для своего случая не вижу?Потому как все варианты идут через вложенный запрос
Я же тебе сказал - в топку Oracle, в топку вложенные запросы во всех их проявлениях.Всё что нужно - адаптировать под свои нужды "хулиганский вариант" от Владимора Конева.Это решение очень даже неплохо ложится на условия твоей задачи и возможности твоего сервера.


pavelsh_chel

Тынц - "хулиганский вариант" и его практическое применение, если что


pavelsh_chel

Тынц - "хулиганский вариант" и его практическое применение, если что
Получилось вот так. Буду еще думать как от substring-ов избавитьсяСпасибо большое за новодку :) Хулиганский вариант рулит!
SELECT H.DEST, H.TARIF, H.PRICE, H.SES_TIME,
RIGHT(MAX(CONCAT(LENGTH(D.CODE),R.PRICE)), <b>6</b>)
FROM RATES R, DEST_CODE D, HOT_STAT H
WHERE D.DEST_ID=R.CODE_ID
	AND D.CODE IN (
 SUBSTRING(H.DEST,<b>1</b>,<b>20</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>19</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>18</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>17</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>16</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>15</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>14</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>13</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>12</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>11</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>10</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>9</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>8</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>7</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>6</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>5</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>4</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>3</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>2</b>),
 SUBSTRING(H.DEST,<b>1</b>,<b>1</b>)
 )
 AND R.RATE_ID='92'
 AND SES_TIME<><b>0</b>
 AND START_DATE>='2007-03-02'
 group by H.CONF_ID, H.START_TIME, H.START_DATE
 ORDER BY START_TIME


pavelsh_chel

Буду еще думать как от substring-ов избавиться
А чего тут думать-то? Заменить их на LIKE и всё... :)
SELECT H.DEST, H.TARIF, H.PRICE, H.SES_TIME, R.PRICE
FROM RATES R, DEST_CODE D, HOT_STAT H
WHERE D.DEST_ID=R.CODE_ID
 AND H.DEST LIKE D.CODE || '%' 
 AND R.RATE_ID='92'
 AND SES_TIME<><b>0</b>


pavelsh_chel

А каким образом bit or мне поможет? Я попробовал все равно на всякий случай и мой сервер так и не смог закончить запрос на минимальных данныхЗатем я попробовал более логичное,
AND H.DEST LIKE CONCAT(D.CODE, '%')


pavelsh_chel

но тоже безрезультатно.


pavelsh_chel

Убить тебя за это мало...Есть гораздо более интересные решения... Приводились и на MySQL ветке форума в том числе...
еще раз хотелось бы спросить, почему убить? :-)посмотрел два "интересных решения", предложенных miksoft:
раз два
в первом предлагается вариант с JOIN по LIKE:
Имхо, нужен индекс на таблице TNumber по полю fnumber.И запрос, если я правильно понимаю его смысл, нужно поправить:
select num.fnumber, max(mask.fmask)
from
TNumber as num left join TMask as mask
on num.fnumber like mask.fmask
GROUP BY num.fnumber
к сожалению, он работает слишком долго (см. ниже)во втором предлагается вариант с UNION:
можно попробовать что-то типа такого:
select * from (
select <b>1</b> rel, pp.* from prefix pp where pp.prefix ='79164855' and length('79164855') between pp.min_len and pp.max_len
union all
select <b>2</b>, pp.* from prefix pp where pp.prefix ='7916485' and length('7916485') between pp.min_len and pp.max_len
union all
select <b>3</b>, pp.* from prefix pp where pp.prefix ='791648' and length('791648') between pp.min_len and pp.max_len
union all
select <b>4</b>, pp.* from prefix pp where pp.prefix ='79164' and length('79164') between pp.min_len and pp.max_len
union all
select <b>5</b>, pp.* from prefix pp where pp.prefix ='7916' and length('7916') between pp.min_len and pp.max_len
union all
select <b>6</b>, pp.* from prefix pp where pp.prefix ='791' and length('791') between pp.min_len and pp.max_len
union all
select <b>7</b>, pp.* from prefix pp where pp.prefix ='79' and length('79') between pp.min_len and pp.max_len
union all
select <b>8</b>, pp.* from prefix pp where pp.prefix ='7' and length('7') between pp.min_len and pp.max_len
order by rel
)
where rownum=<b>1</b>
по сути - это то же самое, что и я предлагал, только UNION нескольких запросов вместо JOINпо скорости у меня работает одинаково - что UNION, что JOINпочитал и про "хулиганский вариант"я так понимаю, в данной задаче он сводится к запросу:
А чего тут думать-то? Заменить их на LIKE и всё... :)
SELECT H.DEST, H.TARIF, H.PRICE, H.SES_TIME, R.PRICE
FROM RATES R, DEST_CODE D, HOT_STAT H
WHERE D.DEST_ID=R.CODE_ID
 AND H.DEST LIKE D.CODE || '%' 
 AND R.RATE_ID='92'
 AND SES_TIME<><b>0</b>
но это то же самое, что вариант №1 miksoft'aмне понадобилось самому решить практически такую же задачу и я решил проверить скорости запросов на простейших таблицах:
CREATE TABLE `callhistory` (
 `id` int(<b>10</b>) unsigned NOT NULL auto_increment,
 `calldate` datetime NOT NULL,
 `phone` varchar(<b>20</b>) NOT NULL
 PRIMARY KEY (`id`),
 KEY `calldate` (`calldate`),
 KEY `phone` (`phone`)
) ENGINE=MyISAM;

CREATE TABLE `prefixes` (
 `id` smallint(<b>5</b>) unsigned NOT NULL auto_increment,
 `prefix` varchar(<b>12</b>) NOT NULL,
 PRIMARY KEY (`id`),
 UNIQUE KEY `prefix` (`prefix`)
) ENGINE=MyISAM;
в таблице callhistory у меня было 200 000 звонков, в prefixes - 7 000 с лишним префиксов (данные реальные)далее делаю два запроса:
SELECT c.calldate, c.phone,
 (SELECT max(prefix) FROM prefixes
 WHERE prefix <= c.phone AND c.phone LIKE CONCAT(prefix, '%')) AS maxprefix
FROM callhistory c

#мой вариант:
SELECT c.calldate, c.phone, IFNULL(...) as maxprefix
FROM callhistory c
LEFT JOIN prefixes p1 ON p1.prefix=LEFT(c.phone, <b>1</b>)
LEFT JOIN prefixes p2 ON p2.prefix=LEFT(c.phone, <b>2</b>)
LEFT JOIN prefixes p3 ON p3.prefix=LEFT(c.phone, <b>3</b>)
...
#и т.д. до длины <b>12</b> :)
в результате мой вариант отрабатывает за 12 сек (при чем скорость зависит от кол-ва длин префиксов, если известно, что префиксы только от 3 до 8 знаков например, то работать в 2 раза быстрее будет), вариант с union 12ти запросов - так же быстроа вот варианты с join по like или с подзапросом (select c.phone,(select max(prefix) from prefixes where prefix like c.phone) from ...) - работают очень долго, отрабатывают примерно за 10 сек но только по 3 тыс. записям вместо 200! (по 200 тыс записям не дождался отработки)вопрос: так чем плох мой вариант? может и "некрасиво", но работает быстрее всего!если вы все же считаете, что за такие запросы надо убивать :-), то просьба написать по-другому конкретный запрос, который на тех же данных отработает быстрее моего, версия mysql у меня 5.0 последняя, можно и подзапросы применять и что угодно - главное скорость работы запроса!explain двух приведенных чуть выше запросов:
id	select_type		table		type	possible_keys	key	key_len	ref	rows	Extra	
<b>1</b>	PRIMARY			c		ALL						<b>232546</b>		
<b>2</b>	DEPENDENT SUBQUERY	prefixes	index	prefix		prefix	<b>14</b>		<b>7228</b>	Using where; Using index	

id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra	
<b>1</b>	SIMPLE		c	index			phone	<b>22</b>		<b>232546</b>	Using index	
<b>1</b>	SIMPLE		p1	eq_ref	prefix		prefix	<b>14</b>	func	<b>1</b>	Using index	
<b>1</b>	SIMPLE		p2	eq_ref	prefix		prefix	<b>14</b>	func	<b>1</b>	Using index	
<b>1</b>	SIMPLE		p3	eq_ref	prefix		prefix	<b>14</b>	func	<b>1</b>	Using index	
<b>1</b>	SIMPLE		p4	eq_ref	prefix		prefix	<b>14</b>	func	<b>1</b>	Using index	
<b>1</b>	SIMPLE		p5	eq_ref	prefix		prefix	<b>14</b>	func	<b>1</b>	Using index	
<b>1</b>	SIMPLE		p6	eq_ref	prefix		prefix	<b>14</b>	func	<b>1</b>	Using index	
<b>1</b>	SIMPLE		p7	eq_ref	prefix		prefix	<b>14</b>	func	<b>1</b>	Using index	
<b>1</b>	SIMPLE		p8	eq_ref	prefix		prefix	<b>14</b>	func	<b>1</b>	Using index	
<b>1</b>	SIMPLE		p9	eq_ref	prefix		prefix	<b>14</b>	func	<b>1</b>	Using index	
<b>1</b>	SIMPLE		p10	eq_ref	prefix		prefix	<b>14</b>	func	<b>1</b>	Using index	
<b>1</b>	SIMPLE		p11	eq_ref	prefix		prefix	<b>14</b>	func	<b>1</b>	Using index	
<b>1</b>	SIMPLE		p12	eq_ref	prefix		prefix	<b>14</b>	func	<b>1</b>	Using index


pavelsh_chel

еще раз хотелось бы спросить, почему убить? :-)
Зачем лазить в таблицу 5 раз, когда всё можно сделать за один?
а вот варианты с join по like - работают очень долго
Если его немного подрихтовать напильничком, то он будет работать куда более шустро. Всё что нужно сделать - добавить ещё одно условие на объединение таблиц, которое позволило бы использовать индекс (если таковой имеется, конечно) по полю с префиксом ...


pavelsh_chel

Зачем лазить в таблицу 5 раз, когда всё можно сделать за один?
потому что у меня получается быстрее вытащить даже 12 раз по одной записи, чем лазить один раз и просматривать таблицу целиком либо большую ее часть
Если его немного подрихтовать напильничком, то он будет работать куда более шустро. Всё что нужно сделать - добавить ещё одно условие на объединение таблиц, которое позволило бы использовать индекс (если таковой имеется, конечно) по полю с префиксом ...
какое условие? вот все, что я смог придумать:
SELECT c.calldate, c.phone, p.prefix
FROM callhistory c LEFT JOIN prefixes p ON c.phone LIKE CONCAT(prefix, '%')
 AND p.prefix <= c.phone				#так
#AND p.prefix LIKE CONCAT(LEFT(c.phone, <b>1</b>), '%')	#или так
WHERE c.calldate >= '2007-02-31'
все равно работает на порядок дольше, чем мои 12 JOIN'овподскажите, как подрихтовать! :-)


pavelsh_chel

потому что у меня получается быстрее вытащить даже 12 раз по одной записи
Кстати, о птичках...Твой вариант сильно зависит от исходных данных. Более того, он не учитывает того факта, что со временем могут появиться более длинные коды. Фактически кол-во джойнов жестко задает максимальную длину кода. При появлении более длинных кодов придется переписывать запрос. Хорошо, если изменение длины кода будет вовремя замечено. В противном случае твой вариант успешно отработает, по некорректно протарифицирует записи.Тут вот порылся в своей биллинговой системе и нашел примерно такие данные, совершенно реальные записи из таблицы с CDR:
Вызываемый номер
Стал смотреть, что там и к чему, выяснилось, что это сотовая связь Швейцарии, доступ через международный узел IP-телефонии.И всё бы было ничего, но вот одно НО: из всего этого номера код направления представляет собой почти весь набор, без последних двух цифр.Фактически этот номер можно разделить вот так:
Вызываемый номер
, где 829910 - это код доступа на международный IP-узел, 4186077357 - код направления (сотовые Швейцарии), 42 - видимо непосредственно остаток от номера.Итого имеем, префикс длиной 16 символов. Чтобы твой вариант нормально оттарифицировал этот разговор нужно таблицу с CDR делать 16 раз джойнить c таблицей с префиксами.Теперь подумай сам, насколько это неоптимально, если средняя длина префикса все-таки составляет всего 8 символов.


pavelsh_chel

какое условие?
Всё зависит от того, как реализовано хранение данных. Разделен ли префикс вызова (8, 810 и т.д.) и код направления по разным таблицам или нет.Кстати, вот ещё такой впорос: не вижу каким местом твой вариант выбирает самый длинный код.Все что делает твой запрос - это находит вообще все коды, которые являются префиксом для данного вызываемого номера. Но этого мало - нужно теперь из всех этих записей выбрать ту, код направления в которой имеет максимальную длину. :)


pavelsh_chel

Разделен ли префикс вызова (8, 810 и т.д.) и код направления по разным таблицам или нет.
разделения нет, но какая разница? даже если я оставлю в таблцие допустим одни префиксы 810, все равно join по like работает ****************, что будет какая-то оптимизация (для телефонов длиной <= 7 префикс не ищем, для межгорода - одни префиксы, для международных - другие, и т.п.), но она будет одинаковая для любого запроса на поиск максимального префикса
Кстати, вот ещё такой впорос: не вижу каким местом твой вариант выбирает самый длинный код. Все что делает твой запрос - это находит вообще все коды, которые являются префиксом для данного вызываемого номера. Но этого мало - нужно теперь из всех этих записей выбрать ту, код направления в которой имеет максимальную длину. :)
мой вариант - это за который меня предлагалось убить :) - с несколькими left join, у меня там не несколько записей получается, а несколько столбцов, среди которых выбирается максимальный префикс в этой строке:
IFNULL(p5.price, IFNULL(p4.price, IFNULL(p3.price, IFNULL(p2.price, IFNULL(p1.price, 'prefix not found'))))) AS price
Твой вариант сильно зависит от исходных данных. Более того, он не учитывает того факта, что со временем могут появиться более длинные коды. Фактически кол-во джойнов жестко задает максимальную длину кода. При появлении более длинных кодов придется переписывать запрос. Хорошо, если изменение длины кода будет вовремя замечено. В противном случае твой вариант успешно отработает, по некорректно протарифицирует записи.
длина телефона жестко ограничена оборудованием - максимум 18 символов, минимальная длина префикса 3, если предположить, что телефон должен содержать хотя бы одну цифру, то надо перебрать 15 префиксов (от 3 до 17), я скорость запросов проверял на 12ти join'ах - разница небольшаяк тому же, число этих join'ов можно определять при каждом импорте списка префиксов
Теперь подумай сам, насколько это неоптимально, если средняя длина префикса все-таки составляет всего 8 символов.
каков критерий оптимальности? у меня - скорость отработки запроса, пока я не смог написать более быстрого запроса, вот и спрашиваю, можно ли это сделать и как? разделение таблицы префиксов какое-то можно и организовать, да и вообще структуру таблиц можно изменить как угодно, лишь бы быстро работало