Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Удалить дубли в таблице [D7, IB6.x]


Страницы:   1 2 3

Vlad ©   (2003-09-25 10:26:00) 

Доброго всем времени суток.
Есть таблица, в которой основные поля: ID (integer,уникальное), Код(integer), Дата(Date), Наименование(Varchar).
Помимо них есть еще штук 15 полей.
Нужно из таблицы удалить дублирующие записи, так, чтобы связка Код-Дата-Наименование стала уникальной.
Проблема в том что в таблице порядка 12 млн записей.
Кто нибудь подскажет наиболее быстрый алгоритм решения задачи, выполнение которого было бы <= 24 часа ?
Все перепробованные мной способы, по предварительным подсчетам, выполнялись быкак минимум трое суток.
Спасибо.


Vlad   (2003-09-25 15:05:00) [21]

>Johnmen © (25.09.03 14:51) [29]
Завтра же утром отпишу подробный отчет :)
Самому интересно.


Vlad   (2003-09-25 15:03:00) [22]

>kaif © (25.09.03 15:00) [32]
Попробую твой способ, но кажется нечто подобное я уже пробовал.
Индексы создаются за приемлемое время. Скажем так, 4 индекса по varchar-полям сегодня утром создал за 40 минут


kaif   (2003-09-25 15:00:00) [23]

А индексировать удается за приемлемое время?


kaif   (2003-09-25 14:56:00) [24]

у меня хранимые процедуры обычно обходят набор со скоростью порядка 30тыс-100тыс записей в секунду. Вставка (insert) блоком в одном запросе insert into ... seletc from происходит достаточно быстро, не хуже 1000 записей в секнду. Правда я не пробовал работать с 12 миллионами. Возможно, вставка в такую таблицу происходит гораздо медленнее, особенно если в ней 15 полей.

Есть еще какой-то левый способ работать с таблицей через номера строк буквально. Как-то об этом шла речь на форуме. Некоторые используют какое-то секретное в IB внутренне для быстрых апдейтов.


Vlad   (2003-09-25 14:56:00) [25]

>kaif © (25.09.03 14:43) [26]
Процент дубликатов мал. Думаю не более 1 млн.
>скопировать все записи, имеющие дубликаты в отдельную таблицу
а чем это быстрее чем просто их удалить ? Все равно время на выборку таких записей будет оч. велико.

>Polevi © (25.09.03 14:48) [27]
Пробовал. Group By сильно гадит по времени. Поскольку индексы тут уже роли не играют. Full Scan так сказать...


Johnmen   (2003-09-25 14:51:00) [26]

>Vlad ©

Когда ожидать отчета о проведенных экспериментах ?
Лично меня интересует сравнение времени [2] и [12].
Да и с [27] тоже...


kaif   (2003-09-25 14:50:00) [27]

А просто переписать все в другую таблицу?
Предположим, IB может сделать 1000 вставок в секунду. 3,6 миллиона вставок за час, то есть 12 миллионов за 4 часа максимум.

insert into table2 select * from AAA;

CREATE PROCEDURE AAA
RETURNS( все поля.....)
AS
DECLARE VARIABLE LAST_CODE INTEGER;
DECLARE VARIABLE LAST_DATA DATE;
DECLARE VARIABLE LAST_NAME VARCHAR(100);
BEGIN
last_code = 0;
last_data= "01.01.1800";
last_name = "";

for select id, code, data, name
from mytable
order by code, data, name //индекс
into :id, :code, :data, :name, ......
do
begin
if ((code <> last_code) or
(data <> last_data) or
(name <> last_name)) then
begin
suspend;
last_code = code;
last_data= data;
last_name = name;
end
end
END


Polevi   (2003-09-25 14:48:00) [28]

DELETE FROM Table WHERE ID NOT IN (
SELECT MAX(ID) FROM Table
GROUP BY Код, Дата, Наимнование)


kaif   (2003-09-25 14:43:00) [29]

2 Vlad © (25.09.03 14:31) [24]
Может быть скопировать все записи, имеющие дубликаты в отдельную таблицу с аналогичной структурой?
Затем убить все записи в первой таблице, используя какой-нибудь неправильный запрос (который я имел в виду) с однократным поздапросом.
Вторую таблицу отфильтровать методом, который предлагает Johnmen.
Затем вставить из второй таблицы записи обратно в первую.

Однако опять тот же вопрос. Какой процент дубликатов?


Johnmen   (2003-09-25 14:38:00) [30]

>kaif © (25.09.03 14:30)

Да перестань извиняться. Со всеми бывает :)
Я могу еще и не такое просмотреть...:)))


Vlad   (2003-09-25 14:31:00) [31]

>kaif © (25.09.03 14:26) [22]
Дык пробовал я такое уже. С индексами.
160 часов - к бабке не ходи !


kaif   (2003-09-25 14:30:00) [32]

2 Johnmen © (25.09.03 14:25) [21]

Да, действительно. Извиняюсь. Я проглядел, что в условии позапроса идет сравнение с полями таблицы основного запроса.

Но тогда он выполнится 12 млн раз!

Я ошибся из-за того, что я никогда не применяю таких запросов (со сравнением полей таблиц запроса и подзапроса)

Дико извиняюсь.


kaif   (2003-09-25 14:26:00) [33]

Процедура, отмечающая дубликаты:

CREATE PROCEDURE AAA
AS
DECLARE VARIABLE ID INTEGER;
DECLARE VARIABLE CODE INTEGER;
DECLARE VARIABLE DATA DATE;
DECLARE VARIABLE NAME VARCHAR(100);
DECLARE VARIABLE LAST_CODE INTEGER;
DECLARE VARIABLE LAST_DATA DATE;
DECLARE VARIABLE LAST_NAME VARCHAR(100);
BEGIN
for select id, code, data, name
from mytable
order by code, data, name //индекс
into :id, :code, :data, :name
do
begin
if ((code = last_code) and
(data = last_data) and
(name = last_name)) then
update mytable set u_field = 1 where id = :id;

last_code = code;
last_data= data;
last_name = name;
end
END


Johnmen   (2003-09-25 14:25:00) [34]

>kaif © (25.09.03 14:11)

Нет. Запрос отработает именно так, как хотел автор.
Вложенный запрос отработает столько раз, сколько записей в таблице.


Vlad   (2003-09-25 14:23:00) [35]

>kaif © (25.09.03 14:11) [17]
Ты ошибаешься. Удалит именно избыточные.
И вложенный запрос будет выполнен ровно столько раз сколько записей в базе.


kaif   (2003-09-25 14:19:00) [36]

Я бы сделал так:
1. добавил бы 1 поле типа INTEGER DEFAULT 0.
2. создал бы неуникальный составной индекс на 3 поля.
3. написал бы хранимую процедуру примерно такую:
обхожу таблицу в порядке этого индекса и вставляю 1 каждый
раз, как только значение трех полей повторяется.
4. Проверяю на глаз, все ли правильно получилось.
5. Удаляю все записи одним DELETE, в которых это поле = 1
6. Удаляю поле.

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


Vlad   (2003-09-25 14:14:00) [37]

>kaif © (25.09.03 14:11) [17]
Ничего, у меня бэкап есть :)


kaif   (2003-09-25 14:11:00) [38]

2 Johnmen © (25.09.03 10:38) [2]

DELETE FROM Table A
WHERE 1<(SELECT COUNT(*) FROM Table B
WHERE (A.Код=B.Код) AND
(A.Дата=B.Дата) AND
(A.Наименование=B.Наименование))


Я боюсь, что этот запрос удалит все записи, которые попадаются неоднократно. А человеку скорее всего нужно удалить избыточныедубликаты, оставив по одной записиот имеющихся дубликатов. Нарушение реляционности конечно требуется, так как неясно, каким экземплярам записей отдать предпочтение.

Так что я боюсь, что это решение ошибочное. Я бы не рискнул применить его на 12 млн. А скорость должна оказаться приемлемой, так как вложенный запрос IB скорее всего выполнит 1 раз.
Но еще раз повторюсь, по-моему тут другая задача.


Sandman25   (2003-09-25 12:10:00) [39]

[15] Johnmen © (25.09.03 11:58)

Я думаю, проблема в неоднозначности - конечный результат зависит от того, "с какого конца" таблицы началось выполнение запроса. При одной стратегии останется первая запись, при другой - последняя. То есть нарушается реляционность (независимость от расположения в таблице), происходит переход к навигационному подходу.


Johnmen   (2003-09-25 11:58:00) [40]

>Sandman25 © (25.09.03 11:28)

Стандартно для IB и клонов, как минимум.
А не идет скорее всего потому, что это работает на версионниках, а не на блокировочниках. Может быть еще связано с алгоритмами оптимизации запросов, а они разные...


Страницы:   1 2 3

Наверх

Титульная страница Поиск, карта сайта Написать письмо