powered by simpleCommunicator - 2.0.60     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Оптимизация join'а большой таблицы с собой же
33 сообщений из 33, показаны все 2 страниц
Оптимизация join'а большой таблицы с собой же
    #39625554
K.T.V.
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Не могу решить задачу:
есть таблица клиентов и их телефонов. Нужно выбрать тех клиентов, у которых телефоны совпадают. Элементарная задачка, если бы не 380000 записей в этой таблице.
Для наглядности:
Код: sql
1.
create table #tempphones (client_id int, clean_phone varchar(128)


В поле clean_phone содержатся только цифры, у одного клиента может быть 1 телефон, у другого 3. Поэтому искать нужно по вхождению. Выбрать нужно всех клиентов, у которых телефоны совпадают.
Самый логичный вариант запроса не отрабатывает даже за 2 часа:
Код: sql
1.
2.
3.
4.
5.
6.
7.
delete from  c1
from #tempphones c1
where not exists (select 1 from #tempphones c2 
					where c2.Client_Id <> c1.Client_Id 
						and 
						(CHARINDEX(c1.clean_phone, c2.clean_phone) > 0 or CHARINDEX(c2.clean_phone, c1.clean_phone) > 0)
					)


Можно избавиться от повторного вызова CHARINDEX, вызывая его только для поиска меньшего телефона в большем. Но это тоже не помогает.
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
alter table #tempphones
add clean_phone_length tinyint

update  #tempphones
set clean_phone_length = len(clean_phone)

delete from  c1
from #tempphones c1
where not exists (select 1 from #tempphones c2 
			where c2.Client_Id <> c1.Client_Id 
				and  
				(case when c1.clean_phone_length > c2.clean_phone_length 
				then CHARINDEX(c2.clean_phone, c1.clean_phone)
				else CHARINDEX(c1.clean_phone, c2.clean_phone)
				end) > 0
			) 


Индексы не помогли ни в одном из вариантов:
Код: sql
1.
2.
create clustered index new1
on #tempphones (clean_phone asc)


Код: sql
1.
2.
create nonclustered index new2
on #tempphones (client_id asc, clean_phone_length asc)


Селект тоже не пашет:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
select * from #tempphones c1
where  exists (select 1 from #tempphones c2 
					where c2.Client_Id <> c1.Client_Id 
						and 
						(CHARINDEX(c1.clean_phone, c2.clean_phone) > 0)
					)
union all
select * from #tempphones c1
where  exists (select 1 from #tempphones c2 
					where c2.Client_Id <> c1.Client_Id 
						and 
						(CHARINDEX(c2.clean_phone, c1.clean_phone) > 0)
					)


Версия сервера 2014.
Мои варианты закончились :(
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625562
Фотография Akina
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
K.T.V.Нужно выбрать тех клиентов, у которых телефоны совпадают.
K.T.V.Самый логичный вариант запроса не отрабатывает даже за 2 часа:
Код: sql
1.
delete from  c1

Ппц логика... надо выбрать? так давайте удалим...

K.T.V.у одного клиента может быть 1 телефон, у другого 3. Поэтому искать нужно по вхождению
А сначала нормализовать данные - не?
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625567
TaPaK
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
K.T.V.,

Сравнивать 1 к 3м телефонам ещё ладно, но 3 к одному просто CHARINDEX явно нельзя. Нормализовать хоть в "право" хоть вниз и потом уже искать, ну и удалять кого из них тоже надо определить
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625568
Руслан Дамирович
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
K.T.V.,

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
WITH
pn AS (
SELECT
  [clean_phone]
FROM
  #tempphones
GROUP BY
  [clean_phone]
HAVING
  --COUNT( DISTINCT [client_id] ) > 1
  COUNT( * ) > 1
)
SELECT
  t.*
FROM
  pn
  INNER JOIN #tempphones t ON (
        t.[clean_phone] = pn.[clean_phone] )
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625569
TaPaK
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Руслан Дамирович,

агонь! Только 3 телефона в одном поле
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625573
Руслан Дамирович
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
TaPaKРуслан Дамирович,
агонь! Только 3 телефона в одном поле
K.T.V.В поле clean_phone содержатся только цифры, у одного клиента может быть 1 телефон, у другого 3
Ну, не очевидно, что ВСЕ ТРИ в одном поле :)
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625579
Руслан Дамирович
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
K.T.V.,
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
IF OBJECT_ID( 'tempdb..#tempphones' ) IS NOT NULL
  DROP TABLE #tempphones
;
IF OBJECT_ID( 'tempdb..#phones' ) IS NOT NULL
  DROP TABLE #phones
;
CREATE TABLE #tempphones ( [client_id] INT, [clean_phone] VARCHAR(128) )
INSERT INTO #tempphones VALUES
( 1, '123456 12345678' ),
( 2, '123456 23456789' )
;
WITH
x AS (
SELECT
  [client_id],
  -- заменить пробел на символ разделителя телефонов
  [xml] = CONVERT( XML, '<i>' + REPLACE( [clean_phone], ' ', '</i><i>' ) + '</i>' )
FROM
  #tempphones
)
SELECT
  [client_id],
  [phone] = n.value( 'text()[1]', 'VARCHAR(10)' )
INTO
  #phones
FROM
  x
  CROSS APPLY x.[xml].[nodes]( '//i' ) t( n )
;
WITH
pn AS (
SELECT
  [phone]
FROM
  #phones
GROUP BY
  [phone]
HAVING
  --COUNT( DISTINCT [client_id] ) > 1
  COUNT( * ) > 1
)
SELECT
  t.*
FROM
  pn
  INNER JOIN #phones t ON (
        t.[phone] = pn.[phone] )
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625580
TaPaK
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
K.T.V.,

вообще в простом случае достаточно, хотя может и упускаю чего...

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
SELECT * 
FROM #tempphones c1
WHERE EXISTS (
		SELECT  1 
		FROM #tempphones c2 
		WHERE  
			c2.Client_Id <> c1.Client_Id	AND
			c2.clean_phone	LIKE '%' + c1.clean_phone '%' COLLATE Latin1_General_100_BIN2
	      )		
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625598
K.T.V.
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
TaPaK, спасибо, но нет. like, тем более с % перед тем что ищем, никак не ускоряет выборку
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625600
K.T.V.
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
К сожалению, данные нормализовать нельзя, только работать над проблемой as is. Нет никакого универсального разделителя телефонов, поэтому нельзя определить, 3 штуки их в поле или 1. Хорошо что договорились, что ищем только вхождение 1го в 3, а не наоборот :)
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625609
K.T.V.
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Руслан Дамирович, я просто убираю из поля телефон все посторонние символы кроме цифр. Поэтому в вашем варианте это будут телефоны
( 1, '12345612345678' ),
( 2, '12345623456789' )
что значительно усложняет задачу
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625613
TaPaK
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
K.T.V.TaPaK, спасибо, но нет. like, тем более с % перед тем что ищем, никак не ускоряет выборку
а я вот совсем не уверен что CHARINDEX быстрее LIKE +BIN в вашем случае
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625643
K.T.V.
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
TaPaK, ну даже не вдаваясь в абстрактные рассуждения, практика показала, что like все равно выполняется недопустимо долго (больше часа)
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625646
TaPaK
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
K.T.V.TaPaK, ну даже не вдаваясь в абстрактные рассуждения, практика показала, что like все равно выполняется недопустимо долго (больше часа)
я так понимаю вы думаете что есть волшебный рашпиль который насравнивает вам значения?

А как вы собираетесь жить когда указано 2 телефона? а + b и у другого b + a? Ну и ещё с десяток таких вариантов
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625656
Руслан Дамирович
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
K.T.V.Руслан Дамирович, я просто убираю из поля телефон все посторонние символы кроме цифр. Поэтому в вашем варианте это будут телефоны
( 1, '12345612345678' ),
( 2, '12345623456789' )
что значительно усложняет задачу
Ну так облегчите себе задачу, и сначала разделите данные, а потом зачистите.
А то прям комсомолом попахивает - стоя в гамаке... лайкаете.
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625667
invm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
K.T.V.К сожалению, данные нормализовать нельзя, только работать над проблемой as is. Нет никакого универсального разделителя телефонов, поэтому нельзя определить, 3 штуки их в поле или 1.Имеем три номера телефона - 1111, 22222 и 333333
Телефоны клиента1, согласно вашим условиям - 111122222
клиента2 - 22222333333

Как и чего будете искать?
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625673
Владислав Колосов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
K.T.V.,

ищИте только точные совпадения, остальное - это мусор, а не номера.
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625675
TaPaK
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Владислав КолосовK.T.V.,

ищИте только точные совпадения, остальное - это мусор, а не номера.
действительно, просто удалите все записи где длинна больше стандартного нормера и всё
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625676
K.T.V.
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ну это не я придумываю идиотские условия.
Нужно, чтобы работал вариант найти телефон 55555 в телефоне 1111111555552222. Остальными пренебрегаем.
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625679
Гавриленко Сергей Алексеевич
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
K.T.V.ну это не я придумываю идиотские условия.
Нужно, чтобы работал вариант найти телефон 55555 в телефоне 1111111555552222. Остальными пренебрегаем.Заодно 55555 будет искаться в паре 44555 и 55666
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625682
Руслан Дамирович
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
K.T.V.ну это не я придумываю идиотские условия.
Нужно, чтобы работал вариант найти телефон 55555 в телефоне 1111111555552222. Остальными пренебрегаем.
Зато в ваших силах обосновать, что условия идиотские, и потому невыполнимые.
Это может повлечь за собой увольнение:
1. а оно вам нужно - дальше хуже;
2. развивайте навыки дипломатии;
3. вы лукавите, и условия совсем не такие, как вы их "не придумали".
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625683
Гавриленко Сергей Алексеевич
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
K.T.V.,

Вот. к примеру, в этих двух склееных строказх (в каждой по 3 телефонных номера) есть совпадения по-вашему:

123456712345681234569 и 12345234561234560

?
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625691
K.T.V.
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Гавриленко Сергей Алексеевич, нет, потому что один телефон клиента полностью должен входить в телефон другого клиента
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625692
Гавриленко Сергей Алексеевич
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
K.T.V.Гавриленко Сергей Алексеевич, нет, потому что один телефон клиента полностью должен входить в телефон другого клиентаА где здесь телефоны клиентов? Здесь две строки, к которым не прилагается алгоритм разбития из на подстроки (телефоны), чтобы потом сравнить хотя бы с неразбитой второй строкой.
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625693
blonduser
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
K.T.V.,
За какое время вы планируете перебрать 144 лярда вариантов?
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625695
Andy_OLAP
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
K.T.V.К сожалению, данные нормализовать нельзя, только работать над проблемой as is. Нет никакого универсального разделителя телефонов, поэтому нельзя определить, 3 штуки их в поле или 1 . Хорошо что договорились, что ищем только вхождение 1го в 3, а не наоборот :)
K.T.V.есть таблица клиентов и их телефонов. Нужно выбрать тех клиентов, у которых телефоны совпадают
Вам по-моему Гавриленко наглядно пояснил.

Ну таки ладно.

Итак, есть клиент1 и телефон 12345. Вполне себе кошерный телефон. И есть клиент2 и клиент3. У клиента2 есть строка, где телефоны "123" и "45678" сливаются в "12345678". Вы не знаете, как делить, но предполагаете своим кодом, что это может быть "12345" и "678". И выводите клиента 2 как совпадающего. Промашка.

Клиент3 имеет телефон "123456", это совсем другой телефон, не "123-45", а "1-234-56", из другой страны префикс. Вы радостно выводите клиента3 как имеющего телефон "12345". Снова промашка.

Вывод - 380 тысяч вариантов по 128 цифр в строке со СЦЕПЛЕННЫМИ номерами телефонов дадут Вам - как верно заметил из предыдущего сообщения коллега - "144 лярда вариантов" (с)

Вы их честно ВСЕ покажете заказчику. Среди них 17 вариантов честных. Не 17 миллионов, не 17 тысяч, а ровно 17 телефонов у клиентов 1 есть у клиентов 2.

Вывод? Задача не имеет решения, потому что решением является выборка честных вариантов, а Вы выдадите на выход пластмассовую иголку в стогу сена, которую магнитом не найти.
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625697
Andy_OLAP
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
K.T.V.,

Еще раз. Абстрагируйтесь от задачи, передохните, погуляйте на свежем воздухе и посмотрите на проблему со стороны.

"Нужно выбрать тех клиентов, у которых телефоны совпадают" - ТЕЛЕФОНЫ, а не куски из цифр, которые слеплены в текстовую строку. ТЕЛЕФОНОВ в такой текстовой строке НЕТ. Есть некая мешанина, хаотичная и бессмысленная.

Заниматься построением логического кода, который что-то выведет - это пустая трата времени.
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625698
blonduser
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Гавриленко Сергей АлексеевичK.T.V.Гавриленко Сергей Алексеевич, нет, потому что один телефон клиента полностью должен входить в телефон другого клиентаА где здесь телефоны клиентов? Здесь две строки, к которым не прилагается алгоритм разбития из на подстроки (телефоны), чтобы потом сравнить хотя бы с неразбитой второй строкой.

Это не номера телефонов, а поиск одной строки в другой.

Алгоритм решения был такой...
Все строки сортируются по кол-ву символов.
Для одного кол-ва символов все варианты сортируются по алфавиту.

И дальше идет соответствующий перебор.
Но вроде такая задача решалась средствами С++
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625737
K.T.V.
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Моя задача с такими условиями имеет быстрое решение. Но т.к. здесь собрались любители увольняться с работы из-за того, что им не предоставили сферические данные в вакууме, очевидно, что постить его смысла не имеет...
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625746
blonduser
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
K.T.V.Моя задача с такими условиями имеет быстрое решение. Но т.к. здесь собрались любители увольняться с работы из-за того, что им не предоставили сферические данные в вакууме, очевидно, что постить его смысла не имеет...

Очень хочется взглянуть на решение. пжлст.
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625750
K.T.V.
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
blonduser, непричесанный вариант:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
create table #tempphones (client_id int, clean_phone varchar(128), clean_phone_with_prefix varchar(128))

;with cte as
(select client_id, clean_phone + '%' as clean_phone, clean_phone as clean_phone_with_prefix
from #tempphones
union all
select client_id, clean_phone, right(clean_phone_with_prefix,LEN(clean_phone_with_prefix)-1) as clean_phone_with_prefix
from cte 
where LEN(clean_phone_with_prefix)>5 --считаем, что меньше 5 цифр не телефон
)
select client_id, clean_phone,clean_phone_with_prefix
into #newtable
from cte

create nonclustered index new1
on #newtable (clean_phone_with_prefix asc)

delete from  c1
from #newtable c1
where not exists (select 1 from #newtable c2 
		where c2.Client_Id <> c1.Client_Id 
		and c2.clean_phone_with_prefix like c1.clean_phone
		)



like по полю + '%' дает возможность оптимизатору использовать индекс, за счет чего поиск значительно ускоряется
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625751
K.T.V.
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
прошу прощения, индекс наверное все же такой:
create nonclustered index new1
on #newtable (clean_phone_with_prefix asc) INCLUDE(client_id)
...
Рейтинг: 0 / 0
Оптимизация join'а большой таблицы с собой же
    #39625804
Гавриленко Сергей Алексеевич
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
K.T.V.Моя задача с такими условиями имеет быстрое решение. Модератор: Ок, потроллили и ладно.
...
Рейтинг: 0 / 0
33 сообщений из 33, показаны все 2 страниц
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Оптимизация join'а большой таблицы с собой же
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]