Как оптимально сравнить две таблицы значений?

1. Nadushka74 5 10.10.14 15:23 Сейчас в теме
наименование колонок и типы данных в колонках идентичны, обе таблицы отсортированы по данным первой колонке. как оптимально произвести их сравнение?
По теме из базы знаний
Вознаграждение за ответ
Показать полностью
Найденные решения
467. ildarovich 7865 02.02.15 12:13 Сейчас в теме
По результатам текущего обсуждения выпущена статья Лучшие методы сравнения таблиц значений.

В ней задача обобщена на случай составного ключа. Для этого все функции переписаны. Также изменено представления результатов сравнения. Это я сделал на свой страх и риск. Возражения принимаются.

Поэтому возможны помарки и может оказаться необходимой перепроверка. Если есть желание - подключайтесь. Обнаружены интересные артефакты, связанные, вероятно с местом хранения строк таблицы значений. Они еще требуют объяснения.

Несколько методов осталось "в запасе". Например, использование нового объекта 8.3, позволяющего рассчитать хэш-функцию. Ну и разные доработки свертки.

Но зато выводы получились очень четкими. Каждому методу нашлось свое место. Буквально таблицу решений по выбору метода можно построить. Посмотрю на результаты обсуждения (если оно будет) и сделаю это.
dj_serega; +1 Ответить
387. ildarovich 7865 05.11.14 23:26 Сейчас в теме
(386) kostyaomsk, причина пояснит приложенная картинка. Это результаты теста при использовании SQL-сервера. Тут есть и запросные (вторая часть строчек) и беззапросные методы. Обратите внимание на последнюю строку. Это время выполнения вот такой процедуры
Функция СравнениеТаблицЗначений(Таблица1, Таблица2, ПрочиеКолонки = "") Экспорт
	
	ИмяКлюча = Таблица1.Колонки[0].Имя;
	
	Для ё = 1 По Таблица1.Колонки.Количество() - 1 Цикл ПрочиеКолонки = ПрочиеКолонки +  ", " + Таблица1.Колонки[ё].Имя
	КонецЦикла;
	
	Запрос = Новый Запрос(
	
	"ВЫБРАТЬ Т.Ключ, -1 КАК Знак
	|ПОМЕСТИТЬ Т1
	|ИЗ	&Таблица1 КАК Т
	|;
	|ВЫБРАТЬ Т.Ключ,  1 КАК Знак
	|ПОМЕСТИТЬ Т2
	|ИЗ	&Таблица2 КАК Т"
	
	);
	
	Запрос.Текст = СтрЗаменить(Запрос.Текст, "Т.Ключ,", ИмяКлюча + " КАК Ключ" + ПрочиеКолонки + ",");
	
	Запрос.УстановитьПараметр("Таблица1", Таблица1);
	Запрос.УстановитьПараметр("Таблица2", Таблица2);
	
	Возврат Запрос.Выполнить().Выгрузить()
	
КонецФункции
Показать
В ней ничего не делается. Никакой обработки. Только производится ввод данных из таблиц значений во временные таблицы. Видите время? - 1896 мс. А за это время - за 1588 мс. свертка уже успела получить и выдать готовый результат!
Конечно, если вычесть это время из времени 2631 самого быстрого запроса полного соединения, то получается, что на обработку SQL потратит меньше времени 735 мс, но вод передача данных в запрос все портит!
Прикрепленные файлы:
411. Никулин Леонид 4 12.11.14 09:33 Сейчас в теме
У меня была похожая задачка. Могу посоветовать выгрузить ТЗ в табличные части и сравнивать их запросом





// Функция сравнивает ТЧ док "ОприходованиеТоваров" и ТЧ док "ЗаказНаПроизводство" (с учетом всех корректировок)
// Если они одинаковые вернет Истину в противном случае Ложь
Функция ПроверкаЗаполненияОприходования(ОприходованиеТоваров,ЗаказНаПроизводство)

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗРЕШЕННЫЕ
| Подсчет.Номенклатура,
| Подсчет.ЕдиницаИзмерения,
| Подсчет.Количество,
| СУММА(Подсчет.Счетчик) КАК СчетчикМин,
| СУММА(Подсчет.Счетчик) КАК СчетчикМакс
|ИЗ
| (ВЫБРАТЬ
| ПотребностиЗаказовНаПроизводство.Номенклатура КАК Номенклатура,
| ПотребностиЗаказовНаПроизводство.ЕдиницаИзмерения КАК ЕдиницаИзмерения,
| ПотребностиЗаказовНаПроизводство.Количество КАК Количество,
| 0.5 КАК Счетчик
| ИЗ
| РегистрНакопления.ПотребностиЗаказовНаПроизводство КАК ПотребностиЗаказовНаПроизводство
| ГДЕ
| ПотребностиЗаказовНаПроизводство.ЗаказНаПроизводство.Ссылка = &ЗаказНаПроизводство
|
| ОБЪЕДИНИТЬ ВСЕ
|
| ВЫБРАТЬ
| ОприходованиеТоваровТовары.Номенклатура,
| ОприходованиеТоваровТовары.ЕдиницаИзмерения,
| ОприходованиеТоваровТовары.Количество,
| 0.5
| ИЗ
| Документ.ОприходованиеТоваров.Товары КАК ОприходованиеТоваровТовары
| ГДЕ
| ОприходованиеТоваровТовары.Ссылка = &ОприходованиеТоваров) КАК Подсчет
|
|СГРУППИРОВАТЬ ПО
| Подсчет.Номенклатура,
| Подсчет.Количество,
| Подсчет.ЕдиницаИзмерения
|ИТОГИ
| МИНИМУМ(СчетчикМин),
| МАКСИМУМ(СчетчикМакс)
|ПО
| ОБЩИЕ";
Запрос.УстановитьПараметр("ОприходованиеТоваров", ОприходованиеТоваров);
Запрос.УстановитьПараметр("ЗаказНаПроизводство", ЗаказНаПроизводство);
Выборка = Запрос.Выполнить().Выбрать();
Выборка.Следующий();

ТЧ_Совпадают = (Выборка.СчетчикМин = Выборка.СчетчикМакс И Выборка.СчетчикМин = 1);

Возврат ТЧ_Совпадают;

КонецФункции
//...-Никулин
Остальные ответы
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
400. awk 741 06.11.14 23:30 Сейчас в теме
(399) ildarovich, По тестированию статью надо. Вопрос что в статье брать? Голая теория которая была нам с вами интересна (так как мы знаем где ее применить, а я уже и применил на заказчике [вряд ли он думал, что его простая задача через такие сложности решена]) не интересна рядовому программисту 1С. Так что все-таки выбор "лучшего" алгоритма надо будет провести по номинациям:

1. Лучший, для быстрого понятия надо ли регистрировать объекты для изменения. Задача обмена.
2. Лучший, для извлечения строк добавлены/изменены/удалены. Задача "Мегадокумента".
3. Поиск дублей в ТЧ. найти задвоенные строки. Задача неповторимости заказа.

Я, кстати, сделал рыбу для отчета анализа производительности, на СКД. Получилось красиво, но думаю надо ли для упр. приложения дорабатывать.


СКД - у меня было где-то. http://infostart.ru/public/80799/, я так к ней и не составил описания. Но таки шустренько работало...
401. dj_serega 392 07.11.14 08:52 Сейчас в теме
(400) awk,
1. Лучший, для быстрого понятия надо ли регистрировать объекты для изменения. Задача обмена.

А можно тут поподробней? :) Подключиться в базу приемник и сравнить объекты?
403. awk 741 07.11.14 10:10 Сейчас в теме
(401) dj_serega, Я про регистрацию объектов для обмена. Чем меньше регистрируется, тем меньше время обмена.
407. dj_serega 392 07.11.14 12:28 Сейчас в теме
(403) awk, А какая идея в проверке "Нужно ли регистрировать или нет"? Хотя бы в 2х словах.
408. awk 741 07.11.14 12:35 Сейчас в теме
(407) dj_serega, Есть документ: Закрытие месяца. Движений строк на 10 000. По COM его не передать (СОМ 32 разрядный, ограничение по оперативке) обмен вылетает. Если брать типовой механизм без проверки, то его надо передавать, а если проверить? С вероятностью 70-80% там ничего не должно поменяться.

Это тяжелый случай. Более простой: "Баба Маша открыла справочник/документ и закрыла с записью." Таких открыли по "ОК" закрыли может накопиться достаточно, для существенного замедления обмена.
409. dj_serega 392 07.11.14 12:42 Сейчас в теме
(408) awk, Ну у меня есть проблема в обмене при обмене ТЧ более 4500 строк. Разбиваю на два. Есть мысль на приемнике собирать обратно в один, но это только идея :)
402. caponid 07.11.14 09:59 Сейчас в теме
(400)
1. Лучший, для быстрого понятия надо ли регистрировать объекты для изменения. Задача обмена.


Точно! :) Надо свою регистрацию в проекте переписать с учетом всего вышеизложенного.
404. Serginio 938 07.11.14 10:23 Сейчас в теме
(399) На самом деле нужно просто показать алгоритмы и не только с одним ключевым полем. Показать где задержки итд. Во многих случаях скорость неважна, а важно удобство применение. Ну и СКД конечно нужно обязательно показать. На локальной БД запрос быстро работает
405. awk 741 07.11.14 10:45 Сейчас в теме
(404) Serginio, Ну если на SSD, то запрос быстрее, а так вровень, в лучшем случае...
406. Serginio 938 07.11.14 10:51 Сейчас в теме
(405) Да там в памяти все кэшурется. Интересно посмотреть на СКД. Сейчас болею, нет под рукой 1С
390. Serginio 938 06.11.14 00:14 Сейчас в теме
(388) Не совсем
Т2=Т2Ориг.Скопировать();
Т2.Индексы.Добавить(ИмяКлюча);


Быстрее чем заполнение Соответствия
386. jobkostya1c_ERP 100 05.11.14 21:23 Сейчас в теме
Все-таки большой вопрос авторам решений и специалистам по оптимизации. Неужели какое-то алгоритм на встроенном языке 1С при обработке двух больших таблиц (хоть и уже точно отсортированных) будет быстрее SQL запроса (когда есть сервер приложений и сервер СУБД)? Эти две больших таблицы нужно как-то получить на сервере приложений. В чем причина то?
387. ildarovich 7865 05.11.14 23:26 Сейчас в теме
(386) kostyaomsk, причина пояснит приложенная картинка. Это результаты теста при использовании SQL-сервера. Тут есть и запросные (вторая часть строчек) и беззапросные методы. Обратите внимание на последнюю строку. Это время выполнения вот такой процедуры
Функция СравнениеТаблицЗначений(Таблица1, Таблица2, ПрочиеКолонки = "") Экспорт
	
	ИмяКлюча = Таблица1.Колонки[0].Имя;
	
	Для ё = 1 По Таблица1.Колонки.Количество() - 1 Цикл ПрочиеКолонки = ПрочиеКолонки +  ", " + Таблица1.Колонки[ё].Имя
	КонецЦикла;
	
	Запрос = Новый Запрос(
	
	"ВЫБРАТЬ Т.Ключ, -1 КАК Знак
	|ПОМЕСТИТЬ Т1
	|ИЗ	&Таблица1 КАК Т
	|;
	|ВЫБРАТЬ Т.Ключ,  1 КАК Знак
	|ПОМЕСТИТЬ Т2
	|ИЗ	&Таблица2 КАК Т"
	
	);
	
	Запрос.Текст = СтрЗаменить(Запрос.Текст, "Т.Ключ,", ИмяКлюча + " КАК Ключ" + ПрочиеКолонки + ",");
	
	Запрос.УстановитьПараметр("Таблица1", Таблица1);
	Запрос.УстановитьПараметр("Таблица2", Таблица2);
	
	Возврат Запрос.Выполнить().Выгрузить()
	
КонецФункции
Показать
В ней ничего не делается. Никакой обработки. Только производится ввод данных из таблиц значений во временные таблицы. Видите время? - 1896 мс. А за это время - за 1588 мс. свертка уже успела получить и выдать готовый результат!
Конечно, если вычесть это время из времени 2631 самого быстрого запроса полного соединения, то получается, что на обработку SQL потратит меньше времени 735 мс, но вод передача данных в запрос все портит!
Прикрепленные файлы:
410. Mell 11.11.14 16:52 Сейчас в теме
Исходя из старт поста запросом, ну а так в зависимости от того какой результат нужен, хотя я бы сравнил запросом, а уже результат отобразил так как это нужно пользователю
411. Никулин Леонид 4 12.11.14 09:33 Сейчас в теме
У меня была похожая задачка. Могу посоветовать выгрузить ТЗ в табличные части и сравнивать их запросом





// Функция сравнивает ТЧ док "ОприходованиеТоваров" и ТЧ док "ЗаказНаПроизводство" (с учетом всех корректировок)
// Если они одинаковые вернет Истину в противном случае Ложь
Функция ПроверкаЗаполненияОприходования(ОприходованиеТоваров,ЗаказНаПроизводство)

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗРЕШЕННЫЕ
| Подсчет.Номенклатура,
| Подсчет.ЕдиницаИзмерения,
| Подсчет.Количество,
| СУММА(Подсчет.Счетчик) КАК СчетчикМин,
| СУММА(Подсчет.Счетчик) КАК СчетчикМакс
|ИЗ
| (ВЫБРАТЬ
| ПотребностиЗаказовНаПроизводство.Номенклатура КАК Номенклатура,
| ПотребностиЗаказовНаПроизводство.ЕдиницаИзмерения КАК ЕдиницаИзмерения,
| ПотребностиЗаказовНаПроизводство.Количество КАК Количество,
| 0.5 КАК Счетчик
| ИЗ
| РегистрНакопления.ПотребностиЗаказовНаПроизводство КАК ПотребностиЗаказовНаПроизводство
| ГДЕ
| ПотребностиЗаказовНаПроизводство.ЗаказНаПроизводство.Ссылка = &ЗаказНаПроизводство
|
| ОБЪЕДИНИТЬ ВСЕ
|
| ВЫБРАТЬ
| ОприходованиеТоваровТовары.Номенклатура,
| ОприходованиеТоваровТовары.ЕдиницаИзмерения,
| ОприходованиеТоваровТовары.Количество,
| 0.5
| ИЗ
| Документ.ОприходованиеТоваров.Товары КАК ОприходованиеТоваровТовары
| ГДЕ
| ОприходованиеТоваровТовары.Ссылка = &ОприходованиеТоваров) КАК Подсчет
|
|СГРУППИРОВАТЬ ПО
| Подсчет.Номенклатура,
| Подсчет.Количество,
| Подсчет.ЕдиницаИзмерения
|ИТОГИ
| МИНИМУМ(СчетчикМин),
| МАКСИМУМ(СчетчикМакс)
|ПО
| ОБЩИЕ";
Запрос.УстановитьПараметр("ОприходованиеТоваров", ОприходованиеТоваров);
Запрос.УстановитьПараметр("ЗаказНаПроизводство", ЗаказНаПроизводство);
Выборка = Запрос.Выполнить().Выбрать();
Выборка.Следующий();

ТЧ_Совпадают = (Выборка.СчетчикМин = Выборка.СчетчикМакс И Выборка.СчетчикМин = 1);

Возврат ТЧ_Совпадают;

КонецФункции
//...-Никулин
445. Leoon 3 18.12.14 11:07 Сейчас в теме
(411) Никулин Леонид,
Зачем выгружать? ТЗ прекрасно читаются запросом через параметр, через описание временной таблицы.
Полное соединение, ну или какая там задача в итоге...
412. alex_sayan 23.11.14 18:02 Сейчас в теме
Никогда не приходилось сравнивать две таблицы значений. Если была задача сравнить две подобные таблицы и выявить между ними различиями, то делал через запрос.
413. dj_serega 392 23.11.14 19:13 Сейчас в теме
где ТС. Медальку кому-то нужно отдать :)
464. Nadushka74 5 12.01.15 07:18 Сейчас в теме
(413) dj_serega, ТС медальки не назначал.
465. dj_serega 392 12.01.15 11:35 Сейчас в теме
(464) Nadushka74, Ну так отдать то может кому-то :)
Правда тут их несколько в итоге появилось.
418. KTo 01.12.14 06:42 Сейчас в теме
Тогда надо четко формулировать задачу. Что значит сравнить?
419. qwinter 671 04.12.14 16:18 Сейчас в теме
Ну и что, подведение итогов будет? Как оптимальнее то?
420. ildarovich 7865 04.12.14 16:42 Сейчас в теме
(419) qwinter, тут, видимо, целую статью придется написать.
В целом получилось примерно так:
1) запрос по-любому проигрывает;
2) свертка, поиск и слияние показывают близкие результаты, причем это получилось после того, как эти методы были предельно аккуратно реализованы. То есть неаккуратная запись слияния, например, может замедлить его в три раза. По моему мнению, свертка лучше. Но так как каждый "болел" за свой метод, то при условии таких близких результатов это можно и оспорить;
3) для статьи интересно было бы задачу чуть расширить. Здесь предполагалось, что ключевая колонка одна, а на практике часто ключ в таблице значений может быть составным (номенклатура-серия, номенклатура-склад). Тогда поиск (соединение) нужно будет делать сразу по двум и более колонкам и "поиск" и некоторые запросы, выигрывавшие сейчас, станут проигрывать.
421. caponid 05.12.14 10:33 Сейчас в теме
Большинство задач (с которыми на данный момент сталкиваюсь) имеют вид

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

так что свой метод я выбрал :-) - свертка показывает отличные результаты.
как запросом так и с ТЗ.

(420) а статья нужна - что бы не потерять остальные наработки.
423. natarezn 07.12.14 15:38 Сейчас в теме
(421) caponid, соглашусь , что это наиболее оптимальная и распространенная вещь
422. natarezn 07.12.14 15:36 Сейчас в теме
Да. лучше делать запросом. выбрать те поля , которые не совпадают.
424. Zixxx 07.12.14 18:39 Сейчас в теме
1. Добавляем четыре колонки "ХешПервойКолонки", "ХешСтроки", "ЕстьРасхождения", "НетСоответствия"
2. Хешируем первую колонку и всю строку таблицы значений, получаем уникальные идентификаторы
3. В цикле пробегаем по первой ТЗ и ищем по Хешу первой колонки совпадения во второй таблице, не нашли значений нет соответствия, если нашли проверяем по Хешу строки, если хеши строки совпадают удаляем эту строку из двух таблиц, если хеши различаются сравниваем значения по колонкам
4. Обходим две таблицы, то что осталось это расхождения, выводим сообщения.
425. Mnemonik 07.12.14 20:05 Сейчас в теме
///////////////////////////////////////////////////////////////////////////////////////
	//ТЗ_1 ТаблицаЗначений
	//ТЗ_2 ТаблицаЗначений
	//две таблицы имеют одинаковое кол-во колонок
	//типы в колонках двух таблиц одинаковые 
	//Количество строк двух таблиц различное
	//В таблицах все строки различны, т.е. каждая таблица не имеет одинаковых строк
	//задача найти различия в двух таблицах
	//форма подачи информации о различиях опускается
	
	КлючСтруктуры = "";
	Ном = 0;
	Для Каждого КолонкаТЗ Из ТЗ_1.Колонки Цикл
		Ном = Ном + 1;
		КлючСтруктуры = КлючСтруктуры + КолонкаТЗ.Имя + ?(ном = ТЗ_1.Количество(), "", ", ");
	КонецЦикла;
	
	ПараметрыПоиска = Новый Структура(КлючСтруктуры);	
	
	//сравнение Таблиц
	МаксИндекс_ТЗ_1 = ТЗ_1.Количество() - 1;
	МаксИндекс_ТЗ_2 = ТЗ_2.Количество() - 1;
	
	КоличествоИтераций = Макс(МаксИндекс_ТЗ_1, МаксИндекс_ТЗ_2);
	
	Для ИндексТЗ = 0 По КоличествоИтераций Цикл
		
		//поиск набора значений в ТЗ_2
		Если ИндексТЗ <= МаксИндекс_ТЗ_1 Тогда
			ЗаполнитьЗначенияСвойств(ПараметрыПоиска, ТЗ_1[ИндексТЗ]);
			МассивСтрок = ТЗ_2.НайтиСтроки(ПараметрыПоиска);
			Если МассивСтрок.Количество() = 0 Тогда
				//набор значений ТЗ_1 не найден в ТЗ_2
				//Сообщить(ИндексТЗ); //для теста
			КонецЕсли;
		КонецЕсли;
		
		//поиск набора значений в ТЗ_1
		Если ИндексТЗ <= МаксИндекс_ТЗ_2 Тогда
			ЗаполнитьЗначенияСвойств(ПараметрыПоиска, ТЗ_2[ИндексТЗ]);
			МассивСтрок = ТЗ_1.НайтиСтроки(ПараметрыПоиска);
			Если МассивСтрок.Количество() = 0 Тогда
				//набор значений ТЗ_2 не найден в ТЗ_1
				//Сообщить(ИндексТЗ); //для теста
			КонецЕсли;
		КонецЕсли;
		
	КонецЦикла;
	
	//если в таблицах допускаются одинаковые строки, то нужно обе талицы сортировать по первой колонке
	//затем в поиске учитывать предыдущий параметр поиска для каждой таблицы,
	//дабы исключить повторное сообщение о различие
////////////////////////////////////////////////////////////­////////////////////////////
Показать
426. пользователь 09.12.14 17:44
Сообщение было скрыто модератором.
...
427. dj_serega 392 09.12.14 18:10 Сейчас в теме
428. awk 741 09.12.14 22:37 Сейчас в теме
(427) dj_serega, В которой запрос не уступает коду. И доказывается это замером 1С в конфигураторе. :)) Может ветку пора закрыть, а то не читатели уже раздражают...
429. Zixxx 09.12.14 22:53 Сейчас в теме
(428) awk, На 100-ом посте это нужно было сделать, так как читатели сами не поняли зачем это им нужно, уперлись в стену тем что у твоего аватара на голове, как думаешь почему?
430. dj_serega 392 09.12.14 23:42 Сейчас в теме
(428) awk, Так ветку еще пару страниц назад нужно было закрывать когда пришли к решению создавать статейку. А вот кому маники отдавать непонятно. Людей много старалось.
Это я намекаю что я читателем был :) Пассивным, но читателем ;)
433. ildarovich 7865 10.12.14 20:03 Сейчас в теме
(428) awk, (430) dj_serega, со статьей пока проблемы - я уперся в то, что та задача, которая честно здесь обсуждалась, с общих позиций может выглядеть частной. И выводы покажутся такими же.

По-хорошему, нужно расширить ее на случай составного ключа - тогда будет покрыт практически весь спектр задач сравнения ТЗ. Но тут нет готового способа поиска для составного ключа. Индекс при составном ключе мало что дает. Нужно использовать ХэшМап. Типа [][][][], как предложил awk. А у меня пока нет времени написать такую реализацию, хотя начал это делать. Все другие способы (даже слияние), легко обобщаются.

Также, по ощущениям, при соединении по нескольким полям в запросе (второй эшелон методов) полное соединение может начать проигрывать свертке в том же запросе. И индексы вряд ли будут помогать.
То есть часть 2 может быть интереснее, чем часть 1, которая легко составляется из того, что есть в нашем обсуждении.

А то, что эта тема висит - ничего страшного - пусть народ думает, пробует и до поры до времени заблуждается.
434. Serginio 938 11.12.14 11:02 Сейчас в теме
(433) Для начала проверь скорость поиска в индексе по нескольким полям и выложи результаты
435. ildarovich 7865 11.12.14 12:17 Сейчас в теме
(434) Serginio, перепроверил скорость поиска, с индексом все хорошо - время поиска практически не зависит от числа строк. То есть загвоздка теперь только в переписывании всех алгоритмов на общий случай составного ключа - там все понятно, нужно только время потратить.
439. Serginio 938 12.12.14 10:39 Сейчас в теме
(435) Для слияния применяй такую функцию

Функция Сравнение(Сравнение,Тз1,Тз2,СпзСписокПолей) 
    
    Для сч=0 По СпзСписокПолей.Количество()-1  Цикл
    Поле=СпзСписокПолей[сч];
    рез=Сравнение.Сравнить(Тз1[Поле],Тз2[Поле]);
    Если рез<>0 Тогда
        Возврат рез;
    КонецЕсли; 

    
КонецЦикла;
Возврат 0;
  
КонецФункции
Показать

Смотри (137)

Можно эту функцию проинлайнить по месту вызова для ускорения

Можно прооптимизировать и закинуть в массив. И сравнивать значения массива. Там фишка в том, что для ТЗ у которой значение больше не нужно повторно обращаться к ТЗ
436. It-developer 24 11.12.14 18:36 Сейчас в теме
(433) Прикол задач оптимизации зачастую именно в том, что их нужно тестировать там, где собираешься оптимизировать. Казалось бы очевидная вещь. Но ...
Вот у меня была задача - как найти по ключу значение в таблице значений. Ключ - обычное число. Таблица отсортирована по ключам. В таблице (она в документе) 100000 элементов. Документов таких 10-к. И вот на выбор 2 варианта просто поиска в одной таблице (по другим не нужно):
1) Бинарный поиск алгоритмом
2) Поиск с использованием НайтиСтроки
3) Запросом
Тест на моем компе ( :)) ) показал, что лучше всего использовать вариант 1. Запрос, кажется, показал результаты в 2 раза хуже. Самый плохой - вариант 2. Но вариант 1 был с данными отсортированного вида и по числовому ключу. Для запроса же грубо говоря все равно по чем искать (но вообще разница есть). Запустили и началось...
Естественно, на магазинах моя "идеальная среда" для поиска показала совершенно противоположные результаты.
Стоит сказать о структуре магазина: 1 комп заведующего, 2 компа касс (подключенных к заведующему) - довольно много старого железа (20-30%).
Итак результат на магазине - жуткие тормоза по варианту 1. А почему? Сама таблица значений очень большая для передачи по сети. Это мой вывод.
В результате победил запрос.
Общий вывод: В каждом случае результат оптимизации может быть свой. Он зависит от многих начальных факторов. Может быть даже такой результат, который "канонами" прописан и чисто с логики 1с должен быть хороший, а на деле нелогичная часть сделает наоборот - хорошую оптимизацию
437. qwinter 671 11.12.14 20:54 Сейчас в теме
(436) It-developer,
Сама таблица значений очень большая для передачи по сети. Это мой вывод.
Если у вас таблица значений, при чем здесь сеть? В файловом варианте таблица значений может существовать только на компьютере оператора в оперативной памяти.
440. It-developer 24 12.12.14 17:39 Сейчас в теме
(437) qwinter, ну и ... прежде чем попасть в эту самую память откуда мы ее берем?
438. ildarovich 7865 12.12.14 00:30 Сейчас в теме
(436) It-developer,
1) ваш вариант из (417) я постараюсь адаптировать, учтя "тонкости" задания, которые вы не заметили и вставлю в общее сравнение, если он покажет хорошие результаты. Пока этого не сделал, но должен.
2) приведенный пример сомнителен (пришлите код - там наверняка в другом было дело, а не в поиске по ключу) и вряд ли пригодится в этой теме. То есть не стоит свой разовый случай так сильно обобщать.
3) вообще при всем при том, что ваш комментарий насыщен терминами "оптимизация", "факторы", по сути он антинаучен. Так как выражает сомнения в нашей способности "познать 1С" и призывает к шаманству. У нас есть все инструменты, чтобы решить любую проблему производительности, просто не всегда это оправдывает затраты времени. Здесь мы хотим потратить время и сделать обоснованные общие выводы с оговорками их применимости к реальным ситуациям, чтобы другим уже это время тратить было не нужно.
441. It-developer 24 12.12.14 17:48 Сейчас в теме
(438) ildarovich, да вы что прямо таки все способы определить любую проблему?
и мы, конечно, знаем что и когда запускал любой пользователь средствами 1с и какая при этом была нагрузка на ЦП и память сервера? :)
техножурналом тока не махайте, пожалуйста :))
"Здесь мы хотим потратить время и сделать обоснованные общие выводы с оговорками их применимости к реальным ситуациям, чтобы другим уже это время тратить было не нужно" на форуме вы ничего не сделаете толкового. Тут больше потрындеть :))
Если нормально, то есть хорошие статьи Гилева по оптимизации клиент-сервера и еще здесь была статья по типам в запросах http://infostart.ru/public/184361/
А вообще самое главное - опыт. Он, конечно, сын ошибок трудных, но для глупцов другого нет (эт я о себе :)) )
431. пользователь 10.12.14 19:43
Сообщение было скрыто модератором.
...
432. ildarovich 7865 10.12.14 19:50 Сейчас в теме
(431) raskol, зачем тут этот спам?
442. kitminsk 205 15.12.14 12:33 Сейчас в теме
Спорят два философа. Один другому:"Вы несете полную чушь!!!". В ответ:"Что такое чушь, что такое полная, что такое несете и кто такой наконец вы???". Может просто выложить эти две таблицы и пускай каждый скажет время сортировки и аппарат на котором делал?
It-developer; +1 Ответить
444. Serginio 938 15.12.14 12:46 Сейчас в теме
(442) Смотри (391) Там файлы прикреплены
443. kitminsk 205 15.12.14 12:34 Сейчас в теме
Р.S. Конечно же не сортировки, а сравнения :)
446. starik-2005 3039 20.12.14 16:10 Сейчас в теме
Можно попробовать сравнить их в цикле типа такого (псевдокод):

For (i=0,j=0;i<count(t1)&&j<count(t2);)
if t1[i][0] = t2[j][0] then
{
eq = true;
for (c=1;c<colcount(t1);c++)
eq &= t1[i][c]==t2[j][c]

if eq then echo "данные для %(t1[i][0]) равны" else echo "данные для %(t1[i][0]) не равны"
j++
i++
}
else {
if t1[i][0] > t2[j][0] then j++ else i++
echo "не равны"
}

Смысл кода таков:
Код подразумевает уникальность первой колонки. Если она не уникальна, то это не сработает
1. сравниваем первую колонку. Если они равны - сравниваем остальные. Если все равны - они равны
2. Если они не равны, то нужно прибавить указатель для "меньшей" по первой колонке таблицы
447. ildarovich 7865 20.12.14 16:14 Сейчас в теме
(446) starik-2005, этот способ здесь назван "слияние" и уже испытан. Показывает неплохие результаты.
448. starik-2005 3039 20.12.14 16:34 Сейчас в теме
Ну у него как раз O(?(N>M,N,M)), у остальных из-за поиска в таблицах эффективность теоретически должна быть меньше. (т.е. минимум O(N * (log M)/2 )
449. starik-2005 3039 20.12.14 16:37 Сейчас в теме
Кстати, читал тут про жадный алгоритм в 3д-пакинге с похожим лицом, полагаю, что напрасно не попробовали сундук/рюкзак для поиска предварительного оптимала при нормализации жадной выборки. Не так уж и медленно 1С работает с массивами.
450. ildarovich 7865 20.12.14 18:09 Сейчас в теме
(449) starik-2005, "напрасно не попробовали" - если имеете ввиду алгоритм, в котором укладка начинается с самых объемных коробок, то как-раз таки попробовал. В предлагаемом там методе критерий выбора коробки на очередном этапе легко перенастраивается. Можно и такой было взять. Взят чуть другой - похожий. Использовать массивы в той задаче мне было не интересно. Но этот вопрос лучше обсуждать в той ветке.

(448) starik-2005, тут ключевое слово "теоретически". У этой теории есть границы применимости, про которые почти все забывают. Поиск в таблице значений при наличии индекса имеет оценку О(1). Можете сами проверить. Поэтому O(N * (log M)/2) - эта формула в данном случае не верна.
451. starik-2005 3039 20.12.14 18:24 Сейчас в теме
(450) ildarovich,
Если индекс - это номер элемента, то да. Как раз при "слиянии" тот самый поиск по индексу ([i]. [j]). Если же приходится искать элемент одной таблицы в другой таблице, то тут скорость падает. Элемент в упорядоченном списке находится по методу деления пополам (двоичное дерево) за "логарифм по основанию два из количества элементов" раз. Таким образом одинарный обход обоих таблиц при единичном сравнении содержимого колонки требует N + M чтений. При одинаковости происходит еще "n * количество колонок" чтений для сравнения колонок. Чем больше одинаковых значений, тем дольше работает алгоритм. Также стоит отметить, чем более одинаковы сравниваемые строки, тем дольше они сравниваются ("абсд" и "абсе" будут сравниваться дольше, чем "ёклмн" и "опрст", т.к. во втором случае первый символ неодинаков - 1 сравнение, в первом узнаем разницу только на 4-м). Но это, конечно, бинарный подход и сравнивать придется в любом случае, поэтому подобное на результат не влияет. Вычисление хэша колонок произведет все те же чтения из таблиц, но при этом при различии уже во второй колонке остановки не будет, а в последовательном сравнении можно сразу же прерваться при наличии неодинаковости и не читать следующие колонки.

По поводу самых объемных коробок вначале, а потом засовыванием туда всего, что сможет влезти - это и есть жадный алгоритм. Рюкзак работает иначе - требует массив для накопления результатов, но при этом возвращает оптимальный результат, с которым потом можно поиграться.
452. ildarovich 7865 20.12.14 18:42 Сейчас в теме
(451) starik-2005,
Если же приходится искать элемент одной таблицы в другой таблице, то тут скорость падает. Элемент в упорядоченном списке находится по методу деления пополам (двоичное дерево) за "логарифм по основанию два из количества элементов" раз.
Вот тут вы заблуждаетесь. При наличии индекса скорость не падает.

Чтобы лучше это понять, представьте индекс как хэш-функцию. Сначала пробегаемся по таблице Т2 и строим хэш-функцию "значение ключа" -> "строка Т2", а затем используем ее для поиска. Это быстро и никак не
логарифм по основанию два из количества элементов.


С рассуждениями о сравнении строк по колонкам на предмет одинаковости тоже можно поспорить - если бы у нас была реальная задача, то можно было бы выбирать для сравнения сначала более информативные колонки. Здесь тесты генерируются "по рандому" и это ничего не дает.

Про задачу о рюкзаке не понял: какой метод ее решения вы имеете ввиду. МВГ? То есть вы предлагаете сначала посчитать объемы, применить МВГ, затем тем же порядком воспользоваться при укладке? - Сомнительно, чтобы такая простая редукция из трехмерной в одномерную задачу работала. Я довольно много литературы тогда пересматривал - там нет очевидных методов, то есть тех, которые можно сходу придумать. Все довольно сложные. Не стоит на эту задачу смотреть свысока - она действительно сложная.
453. starik-2005 3039 21.12.14 13:26 Сейчас в теме
(452) ildarovich, В принципе, если хеш создается для некоторого вектора, являющегося содержимым строки таблицы, то сначала создается вектор с чтением всех строк, потом кладется в еще одну таблицу. Т.е. происходит чтение всего из обоих таблиц, что равно O ( (N + M) * C ), где C - количество колонок. Дальше мы сравниваем хэши, т.е. производим еще примерно N + M чтений. Итого: O ( (N + M) * C + N + M ). Для слияния будет иначе: мы читаем N + M + C / 2, если принять. что несовпадающие элементы среднераспределены по колонкам. Если же содержимое крайне неоднородно, то С/2 будет уже С/3...С. Если колонки организовать таким образом, чтобы во вторую попадало как можно более неоднородное содержание, а самое однородное - в последнюю, то все будет стремиться к всего двум сравнениям - индекса и второй колонки. Изредка могут встречаться ситуации, когда вторые колонки окажутся одинаковыми, но следующая колонка окажется одинаковой еще в меньшем количестве случаев, если у нас колонки будут идти по уровню разнородности содержимого.

Вообще, можно попробовать менять местами колонки и протестировать эффективность алгоритма при таком подходе. Было бы интересно наблюдать такие результаты.

По поводу сложности 3д-упаковки. то я нисколько не сомневаюсь, что задача сложная. Но адаптация рбкзака к объему тем не менее вполне реализуемая вещь. Я использовал рюкзак для задач "2д", но сначала выбирал оптимал по одному измерению, а потом жадным алгоритмом выбирал распределение на второе и использовал опимизирующие перстановки. Можно было бы сделать сразу на двух, ведь стандартная задача о рюкзаке использует два измерения - вес и цена. Также несложно адаптировать его и для трех измерений, просто памяти придется потратить больше и это уже задача не для 1С. Я свой в итоге на ASM переписал - очень все быстро работает, хотя злые языки и утверждают, что на процессорах с длинным конвейером С дает результаты не хуже, а зачастую и лучше - не проверял.
454. ildarovich 7865 21.12.14 16:07 Сейчас в теме
(453) starik-2005, в целом все так.
Плюс к этому было рассмотрено выше в этом топике еще несколько способов. Эти способы были тщательно оттюнингованы, поскольку оказалось, что разница в быстродействии при одинаковом характере зависимости определяется тщательностью исполнения. То есть практически получилось, что разные по природе способы показывают примерно одинаковую зависимость быстродействия от размера сравниваемых таблиц. Текущая сводка результатов приведена в (391). Есть мысль чуть обобщить задачу и статью написать. Пока не очень получается из-за времени.
К вопросу о порядке сравнения колонок.
На тестах ТЗ были случайными и порядок роли не играл. Для реальной задачи можно предложить не просто сортировать колонки по информативности Сумма(p Log p), а строить ДЕРЕВО РЕШЕНИЙ поиска строки, в котором на каждом шаге будет находиться наиболее информативный параметр. В 1С в анализе данных есть похожий метод, но вряд ли стоит с этим заморачиваться на 1С. Решение получается громоздким, а испытанные методы и так достаточно хороши.

По-поводу рюкзака и 3Д-упаковки.
Чтобы решать эту задачу на уровне ведущих алгоритмов, нужно сделать это своей областью научных интересов. Посмотрите список литературы по теме Container Loading. Этим целые научные школы и коллективы занимаются. 3DPacker, по-моему, команда из МГУ разрабатывает, монографии на эту тему пишет. Надеяться на то, чтобы изобрести из умозрительных соображений метод, который вдруг будет их обходить можно, но я тут пессимистично настроен. В это нужно впрягаться. Можно и на Си, и на ASM и на CUDA это делать. А кто будет за это платить?
Моя задача была за короткое время сделать компактный работоспособный метод без использования ВК. Я это сделал и уже оставил эту задачу. Правда, есть версия по УФ для УТ11, которую я никак не дотестирую, чтобы попытаться продать, но серьезного денежного интереса я не увидел - в основном любопытство.
455. starik-2005 3039 21.12.14 16:46 Сейчас в теме
(454) ildarovich,
Любопытство всегда двигало вперед многое в этом мире, а вот отсутствие любопытства губит профессионалов и способствует профессиональному выгоранию (ну и алкоголь еще в придачу).

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

*
----------
Стандартное отклонение является одним из тех статистических терминов в корпоративном мире, которое позволяет поднять авторитет людей, сумевших удачно ввернуть его в ходе беседы или презентации, и оставляет смутное недопонимание тех, кто не знает, что это такое, но стесняется спросить. На самом деле большинство менеджеров не понимают концепцию стандартного отклонения и, если вы один из них, вам пора перестать жить во лжи. В сегодняшней статье я расскажу вам, как эта недооцененная статистическая мера позволит лучше понять данные, с которыми вы работаете.
-----------
456. ildarovich 7865 22.12.14 10:07 Сейчас в теме
(455) starik-2005, позанудствую немного по-поводу стандартного отклонения.
здравый смысл говорит, что чем выше стандартное отклонение*, тем ближе его можно засунуть к началу
Тут вы нашли знакомую вам меру, позволяющую определить порядок колонок, но этот выбор конкретно не правильный.

Правильная мера, которая будет в среднем снижать до минимума необходимое число сравнений при сравнении двух строк - это "информативность" данных колонки. Полученная по формуле Сумма(Pj log Pj), где Pj - это частота появления значения j в колонке. Информативность - это число бит, которым можно закодировать данные колонки. То есть сначала нужно сравнивать данные наименее сжимаемых колонок. Близкое понятие - селективность индекса. В случае стандартного отклонения вы легко обманетесь - пойдете по долгому пути, выбрав сначала колонку (-1000, +1000, -1000, + 1000, ...) вместо колонки (0.1, 0.2, 0.3, 0.4, ...).
457. starik-2005 3039 22.12.14 18:24 Сейчас в теме
(456) ildarovich,
Вы в этом правы. Просто стандартное отклонение - то, что приходит на ум в первую очередь, т.к. оно отражает разбросы относительно среднего значения. Есть коэффициент "чувствительности", про который я в сети не нашел информации, но который применяется для анализа временного ряда, определяя качественную степень сравнения двух таких рядов для поиска синхронного соответствия.

"Шумность", как информативность, рассматривать достаточно правильно, но затраты времени и памяти здесь выше. Поэтому идеально определить информативность колонок на какой-то предварительной тестовой выборке и построить рейтинг колонок на основании ее одномоментно, после чего использовать полученную конфигурацию в продукте.
458. DrAku1a 1718 25.12.14 08:08 Сейчас в теме
Если нужно сравнить на идентичность, то может попробовать такое извращение:
ЗначениеВСтрокуВнутр(ТЗ1)<>ЗначениеВСтрокуВнутр(ТЗ2)
truba; Восьмой; +2 Ответить
459. ildarovich 7865 25.12.14 11:23 Сейчас в теме
(458) DrAku1a, предлагалось в (64) уже.
460. starik-2005 3039 25.12.14 15:52 Сейчас в теме
(458) DrAku1a, это только в случае, если не нужно видеть разницу.
Восьмой; +1 Ответить
461. truba 27.12.14 14:13 Сейчас в теме
Тупо преобразовать обе таблицы в текст и сравнить до первого расходящегося символа.
о, было выше. идеи носятся в морозном воздухе
462. Yashazz 4727 31.12.14 16:23 Сейчас в теме
Однажды мне надоели стандартные заходы (обычно использовал примерно то, что предлагал Ильдарович), и я извратился - сериализовал обе таблицы и использовал методы DOM-объекта насчёт идентичности узлов и прочая. Так вот, сравнивает быстро, результаты можно подавать красиво, но скорость самой сериализации... ниже плинтуса. Однако же пусть будет в копилке маразмов)))
ildarovich; +1 Ответить
463. Slon1c 11.01.15 14:46 Сейчас в теме
Похожая ситуация возникала при решении задачи показать различия в наборах записей при перепроведении документа без изменения его старых записей, для создания корректировок в текущем периоде.
Для регистров хозрасчетный и накопления все реализовалось просто - числовые - суммирующие, все остальные как составной ключ (без учета номера строки и регистратора). Удаляем все нулевые по ключу, далее быстренько все сравнивалось. А вот с не числовыми полями - сравнения оптимально сделать так и не удалось (регистр сведений). Пришлось полностью отказаться от такой проверки, так как не понятно как выводить разницу между качественными показателями. Что значит вывести разницу между красным и желтым ? да, они различны, но как это представить не понятно. Если не выводить разницу . то проще использовать функцию сравнить(Значение1, значение2). где значения - имеет тип значения - произвольный :). Простой первичный код с выводом разницы для числовых значений (оптимизированный впоследствии) :

Функция СторнироватьТаблицуСтруктуры(ДвиженияСтало, ДвиженияБыло, ВидРегистров)
Результат = Новый Структура;

Таблица = Неопределено;
Для каждого строкаСторноТаблица из ДвиженияБыло Цикл

ТаблицаРегистра = строкаСторноТаблица.Значение.Скопировать();

ТаблицаРегистра.ЗаполнитьЗначения(0, "НомерСтроки");
ТаблицаРегистра.ЗаполнитьЗначения(0, "Регистратор");

лкФлагПоследнего = ТаблицаРегистра.Колонки.Количество()-1;

Имя = "";
Число = Ложь;
СуммирующиеКолонки = "";
ГруппировочныеКолонки = "";

Для Значение=0 По лкФлагПоследнего Цикл
Имя = строка(ТаблицаРегистра.Колонки[Значение].Имя);
Если Найти(Имя,"Номер") = 0 Тогда
Число = ТаблицаРегистра.Колонки[Значение].ТипЗначения.СодержитТип(Тип("Число"));
СуммирующиеКолонки = ?(Число, СуммирующиеКолонки+?(СуммирующиеКолонки = "","",",")+Имя,СуммирующиеКолонки);
ГруппировочныеКолонки = ?(Число, ГруппировочныеКолонки,ГруппировочныеКолонки+?(ГруппировочныеКолонки = "","",",")+Имя);
КонецЕсли;
КонецЦикла;

ТаблицаРегистра.Свернуть(ГруппировочныеКолонки,СуммирующиеКолонки);
ИнвентироватьТаблицу(ТаблицаРегистра,СуммирующиеКолонки);

лкТаблица = Новый ТаблицаЗначений;

Если ДвиженияСтало.Свойство(строкаСторноТаблица.Ключ,лкТаблица) Тогда
лкТаблица = лкТаблица.Скопировать();

Если лкТаблица.Колонки.Найти("НомерСтроки") <> Неопределено Тогда
лкТаблица.ЗаполнитьЗначения(0, "НомерСтроки");
КонецЕсли;
Если лкТаблица.Колонки.Найти("Регистратор") <> Неопределено Тогда
лкТаблица.ЗаполнитьЗначения(0, "Регистратор");
КонецЕсли;

лкТаблица.Свернуть(ГруппировочныеКолонки,СуммирующиеКолонки);
Для каждого лкстрока из лкТаблица Цикл
НоваяСтрока = ТаблицаРегистра.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока,лкстрока);
КонецЦикла;
ТаблицаРегистра.Свернуть(ГруппировочныеКолонки,СуммирующиеКолонки);
КонецЕсли;

ТаблицаРегистра = УдалитьСтрокиСПустымиСуммирующиеКолонки(ТаблицаРегистра,СуммирующиеКолонки);

Результат.Вставить(строкаСторноТаблица.Ключ, ТаблицаРегистра);
Если ВидРегистров = 1 Тогда
Строка = Регистры[режРазница].ТаблицаРегистровБухгалтерии.Добавить();
Строка.Имя = строкаСторноТаблица.Ключ;
Строка.Представление = Метаданные.РегистрыБухгалтерии.Найти(строкаСторноТаблица.Ключ).Синоним;
ИначеЕсли ВидРегистров = 2 Тогда
Строка = Регистры[режРазница].ТаблицаРегистровНакопления.Добавить();
Строка.Имя = строкаСторноТаблица.Ключ;
Строка.Представление = Метаданные.РегистрыНакопления.Найти(строкаСторноТаблица.Ключ).Синоним;
ИначеЕсли ВидРегистров = 3 Тогда
Строка = Регистры[режРазница].ТаблицаРегистровСведений.Добавить();
Строка.Имя = строкаСторноТаблица.Ключ;
Строка.Представление = Метаданные.РегистрыСведений.Найти(строкаСторноТаблица.Ключ).Синоним;
КонецЕсли;

КонецЦикла;

Для каждого Строка Из ДвиженияСтало Цикл

Если не Результат.Свойство(Строка.Ключ) Тогда
Результат.Вставить(Строка.Ключ, Строка.Значение.Скопировать());
Если ВидРегистров = 1 Тогда
НоваяСтрока = Регистры[режРазница].ТаблицаРегистровБухгалтерии.Добавить();
НоваяСтрока.Имя = Строка.Ключ;
НоваяСтрока.Представление = Метаданные.РегистрыБухгалтерии.Найти(Строка.Ключ).Синоним;
ИначеЕсли ВидРегистров = 2 Тогда
НоваяСтрока = Регистры[режРазница].ТаблицаРегистровНакопления.Добавить();
НоваяСтрока.Имя = Строка.Ключ;
НоваяСтрока.Представление = Метаданные.РегистрыНакопления.Найти(Строка.Ключ).Синоним;
ИначеЕсли ВидРегистров = 3 Тогда
НоваяСтрока = Регистры[режРазница].ТаблицаРегистровСведений.Добавить();
НоваяСтрока.Имя = Строка.Ключ;
НоваяСтрока.Представление = Метаданные.РегистрыСведений.Найти(Строка.Ключ).Синоним;
КонецЕсли;

КонецЕсли;

КонецЦикла;

Возврат Результат;

КонецФункции

Функция ИнвентироватьТаблицу(лкТаб,СуммирующиеКолонки)

Колонки = СуммирующиеКолонки ;
Основной = Колонки;

Для каждого Строка из лкТаб Цикл
Колонки = Основной;
Счетчик = СтрЧислоВхождений(Колонки,",");
Для индекс = 1 по Счетчик + 1 Цикл
НомерСимвола = Найти(Колонки,",");
Колонка = Сред(Колонки,1,НомерСимвола-1);
Строка[Колонка] = (-1)* Строка[Колонка];
Колонки = Сред(Колонки,НомерСимвола+1,СтрДлина(Колонки));
КонецЦикла;
КонецЦикла;

Возврат лкТаб

КонецФункции
466. cheiser1982 215 13.01.15 13:18 Сейчас в теме
Задача следующая: необходимо сформировать таблицу, из которой нужно убрать все записи, которые совпадают с записями регистра сведений (исключаем из т.з. записи, совпадающие по нескольким полям с записями регистра сведений).

Хочу продемонстрировать свой запрос, который выполняет данную работу. Думаю подходит к вашей теме:

Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("ТЗПараметр", Объект.ТаблицаПоказанийСчетчиков.Выгрузить());
	Запрос.Текст =
	"ВЫБРАТЬ РАЗЛИЧНЫЕ
	|	ТЗПараметр.Контрагент,
	|	ТЗПараметр.Счетчик,
	|	ТЗПараметр.МестоУстановки,
	|	ТЗПараметр.ДатаУстановки,
	|	ТЗПараметр.ДатаОкончанияПоверки
	|ПОМЕСТИТЬ ИсходнаяТаблица
	|ИЗ
	|	&ТЗПараметр КАК ТЗПараметр
	|;
	|
	|////////////////////////////////////////////////////////////­////////////////////
	|ВЫБРАТЬ РАЗЛИЧНЫЕ
	|	ДанныеОбИспользованииСчетчиков.ДатаУстановки КАК ДатаУстановки,
	|	ДанныеОбИспользованииСчетчиков.Контрагент,
	|	ДанныеОбИспользованииСчетчиков.Счетчик
	|ПОМЕСТИТЬ ДанныеРегистра
	|ИЗ
	|	РегистрСведений.ДанныеОбИспользованииСчетчиков КАК ДанныеОбИспользованииСчетчиков
	|
	|ИНДЕКСИРОВАТЬ ПО
	|	ДатаУстановки
	|;
	|
	|////////////////////////////////////////////////////////////­////////////////////
	|ВЫБРАТЬ
	|	ТаблицаДатБезПовторений.Контрагент,
	|	ТаблицаДатБезПовторений.Счетчик,
	|	ТаблицаДатБезПовторений.МестоУстановки,
	|	ТаблицаДатБезПовторений.ДатаУстановки КАК ДатаУстановки,
	|	ТаблицаДатБезПовторений.ДатаОкончанияПоверки,
	|	ЕСТЬNULL(ДанныеРегистра.ДатаУстановки, 0) КАК ДатаУстановкиРег,
	|	ЕСТЬNULL(ДанныеРегистра.Контрагент, 0) КАК КонтрагентРег,
	|	ЕСТЬNULL(ДанныеРегистра.Счетчик, 0) КАК СчетчикРег
	|ПОМЕСТИТЬ ПолноеСоединениеТаблиц
	|ИЗ
	|	ИсходнаяТаблица КАК ТаблицаДатБезПовторений
	|		ПОЛНОЕ СОЕДИНЕНИЕ ДанныеРегистра КАК ДанныеРегистра
	|		ПО ТаблицаДатБезПовторений.ДатаУстановки = ДанныеРегистра.ДатаУстановки
	|			И ТаблицаДатБезПовторений.Счетчик = ДанныеРегистра.Счетчик
	|			И ТаблицаДатБезПовторений.Контрагент = ДанныеРегистра.Контрагент
	|;
	|
	|////////////////////////////////////////////////////////////­////////////////////
	|ВЫБРАТЬ
	|	ПолноеСоединениеТаблиц.Контрагент,
	|	ПолноеСоединениеТаблиц.Счетчик,
	|	ПолноеСоединениеТаблиц.МестоУстановки,
	|	ПолноеСоединениеТаблиц.ДатаОкончанияПоверки,
	|	ПолноеСоединениеТаблиц.ДатаУстановки
	|ИЗ
	|	ПолноеСоединениеТаблиц КАК ПолноеСоединениеТаблиц
	|ГДЕ
	|	ПолноеСоединениеТаблиц.ДатаУстановкиРег = 0
	|	И ПолноеСоединениеТаблиц.КонтрагентРег = 0
	|	И ПолноеСоединениеТаблиц.СчетчикРег = 0";
	
	МассивРезультатовЗапроса = Запрос.ВыполнитьПакет();
	ИтоговаяТаблица = МассивРезультатовЗапроса[3].Выгрузить();
Показать


Немного поясню:
1. Создаем из нашей ТЗ временную таблицу в запросе;
2. Выбираем данные из регистра сведений;
3. Выполняем полное соединение сформированных выше таблиц. Данным, которые не найдены в регистре присваиваем 0.
4. И напоследок, отбираем занулившиеся на предыдущем шаге записи.

Возможно запрос не очень оптимален - делал на скорую руку, но думаю смысл донес.
kabantus; +1 Ответить
467. ildarovich 7865 02.02.15 12:13 Сейчас в теме
По результатам текущего обсуждения выпущена статья Лучшие методы сравнения таблиц значений.

В ней задача обобщена на случай составного ключа. Для этого все функции переписаны. Также изменено представления результатов сравнения. Это я сделал на свой страх и риск. Возражения принимаются.

Поэтому возможны помарки и может оказаться необходимой перепроверка. Если есть желание - подключайтесь. Обнаружены интересные артефакты, связанные, вероятно с местом хранения строк таблицы значений. Они еще требуют объяснения.

Несколько методов осталось "в запасе". Например, использование нового объекта 8.3, позволяющего рассчитать хэш-функцию. Ну и разные доработки свертки.

Но зато выводы получились очень четкими. Каждому методу нашлось свое место. Буквально таблицу решений по выбору метода можно построить. Посмотрю на результаты обсуждения (если оно будет) и сделаю это.
dj_serega; +1 Ответить
468. vatkir 7 05.08.21 16:09 Сейчас в теме
В БСП есть функция сравнения таблиц, коллекций, даже если они разного типа (например ТаблицаЗначений и ДанныеФормыКоллекция).
см ОбщегоНазначения.КоллекцииИдентичны()
user1559729; +1 Ответить
Оставьте свое сообщение

Для получения уведомлений об ответах подключите телеграм бот:
Инфостарт бот