Здравствуйте. Каковы общие рекомендации по оптимизации кода PQ, что в общих случаях будет быстрее какой код более оптимизирован, из имеющихся, тот который создает столбец, или тот который делает построчную замену?
Что на Ваш взгляд будет быстрее из следующих вариантов:
этот, Вариант с созданием колонки и записью в нее данных по условию,
Код
= Table.RenameColumns(
Table.RemoveColumns(
Table.AddColumn(
Table.AddColumn(ISTO4NIK, "NewColumn", each "NewValue"),
"TEMPColumn", each (if [NewColumn]<>null then [NewColumn] else [OldColumn])
)
{"OldColumn","NewColumn"}
),
{{"TEMPColumn", "OldColumn"}})
или, Вариант с построчной заменой по условию
Код
= Table.RemoveColumns(
Table.ReplaceValue(
Table.AddColumn(ISTO4NIK, "NewColumn", each "NewValue"),
each [OldColumn], each (if [NewColumn]<>null then [NewColumn] else [OldColumn]),
Replacer.ReplaceValue, {"OldColumn"}),
{"NewColumn"}
)
Андрей VG, Спасибо за участие! Но все-таки, зачем же Вы сразу издеваетесь то над еще малоопытным пользователем? Понятно что значение в столбце одно, и поэтому его можно сразу трансформировать в другой столбец. А, если,значение в новом столбце, все-таки будут с нулевыми строками? или с каким-то другим значением, для выборки? Что будет быстрее тогда?
lostandleft, а в чем проблема сгенерить таблицу на 1кк строк и протестировать оба ваших варианта с секундомером наперевес? Мы тут время от времени такими плюшками балуемся.
lostandleft написал: зачем же Вы сразу издеваетесь
То есть выложить в качестве примера хрень - это нормально? Я же
Цитата
lostandleft написал: еще малоопытным пользователем?
Подобное в детском саду - хорошее оправдание Но, добро пожаловать во взрослую жизнь.
Цитата
lostandleft написал: А, если,значение в новом столбце, все-таки будут с нулевыми строками?
Что значит с нулевыми строками? Будьте столь любезны пример приложить? Или вас нужно уговаривать? А в рамках вашего примера, максимум что можно выжать, так это заменить значения null с столбце OldColumn - так для этого вполне и Table.TransformColumn хватит. P. S. И добрый совет - не увлекайтесь вложенными функциями - теряете читабельность кода. Любой текст удобнее читать слева на право и с верху вниз
Довел количество строк до 1 млн, скопировав последнюю строчку в конец листа.
Написал 2 варианта кода:
Вариант 1:
Код
let
Источник = Table.NestedJoin(Таблица1, {"Груз"}, Таблица2, {"Груз"}, "Таблица2", JoinKind.LeftOuter),
#"Развернутый элемент Таблица2" =
Table.RenameColumns(
Table.RemoveColumns(
Table.AddColumn(
Table.AddColumn(
Table.ExpandTableColumn(Источник, "Таблица2", {"Цена"}, {"Цена"}),
"NewColumn", each "NewValue"),
"TEMPColumn", each (if [NewColumn]<>null then [NewColumn] else [Цена])
),
{"NewColumn", "Цена"}
),
{{"TEMPColumn", "Цена"}})
in
#"Развернутый элемент Таблица2"
Вариант 2:
Код
let
Источник = Table.NestedJoin(Таблица1, {"Груз"}, Таблица2, {"Груз"}, "Таблица2", JoinKind.LeftOuter),
#"Развернутый элемент Таблица2" =
Table.RemoveColumns(
Table.ReplaceValue(
Table.AddColumn(Table.ExpandTableColumn(Источник, "Таблица2", {"Цена"}, {"Цена"}),
"NewColumn", each "NewValue"),
each [Цена], each (if [NewColumn]<>null then [NewColumn] else [Цена]),
Replacer.ReplaceValue, {"Цена"}),
{"NewColumn"}
)
in
#"Развернутый элемент Таблица2"
Как Оказалось вариант 1, работает почти в 2 раза быстрее, т.е. следует избегать repalce, и все делать через дополнительный столбец...жаль я не проверил этого ранее
Андрей VG написал: P. S. И добрый совет - не увлекайтесь вложенными функциями - теряете читабельность кода.
Категорически стараюсь увлечься, и напротив, научиться писать все в одной переменной, стараюсь делать комментарии, пока не очень получается, но вдохновило на это статья: Оптимизация производительности PQ пока что получается криво, но я стараюсь. Просто по 30-40 минут ожидать исполнения запроса - глупо. Кроме того, если переменных будет десятка 3, то читать код еще труднее. По мне, лучше 5 пременных с вложенным десятком функций и комментариями рядом, чем 50 переменных ссылающихся друг на друга.
Андрей VG, Можете помочь написать функцию, которая будет добавлять столбец и выполнять проверку по условию? В Функции в качестве вводных указывать 1 - Столбец со значениями в которых нужно делать изменения 2 - Столбец со значениями из которого нужно что-то выбрать. 3 - Условие для сравнения, null, Какое-тоЗначение, или какой-нибудь результат от других вычислений.
Код
(if [NewColumn]<>"КакоеТоЗначение" then [NewColumn] else [КолонкаДляПреобразованийИсходная])
Михаил Л, Сомневаюсь, но верю в истинность, при объявлении каждой новой переменной, по ощущениям PQ выполняет весь запрос заново. Это особенно хорошо видно на огромных файлах и на запросах в сторонние книги. На каждой новой переменной PQ заново все просчитывает, поэтому число переменных утяжеляет код и увеличивает время в геометрической прогрессии.
Это мои ощущения, но возможно я что-то чувствую иначе.
Михаил Л, 13 секунд против 26 на моем компьютере, попробуйте на своем. Создайте 2 запроса в одной книге. Оба запроса я вывел из фонового режима и включил быструю загрузку
PooHkrd, для меня важнее суть, и благодарность за перевод, нежели авторское право, я ведь о производительности вопрос задал. Хоттелось бы оптимизировать свои запросы. Уж очень они долгие.
Поверьте, количество переменных в запросе новичка, это последнее что влияет на производительность. Чтобы помочь не на пальцах, это нужно сидеть рядом с вами и по косточкам разбирать ваш код и ваши источники.
PooHkrd написал: это нужно сидеть рядом с вами и по косточкам разбирать ваш код и ваши источники
Эх, я понимаю. Но вариант с колонкой на замену REPLACER реально увеличивает производстельность в1,8-2 раза! Наверняка еще масса таких хитростей есть. Я этого не знал, старался везде реплейсер ставить, просто потому что код меньше. Получается это неправильно. Кто-бы с функцией подмогнул :-)
lostandleft написал: Можете помочь написать функцию, которая будет добавлять столбец и выполнять проверку по условию?
Не вопрос, если
Цитата
2.3. Приложите файл(ы) с примером (общим весом не более 300Кб) в реальной структуре и форматах данных того, что есть сейчас и того, что хотелось бы на выходе.
lostandleft написал: при объявлении каждой новой переменной, по ощущениям PQ выполняет весь запрос заново.
это только в редакторе при разработке - ему нужно сгенерировать для вас предпросмотр состояния запроса на конкретный шаг и закэшировать его. При рабочем выполнении запроса ему плевать на предпросмотр, поэтому работает совсем не так. Вообще любой сколь угодно сложный код PQ можно записать вообще в одну строку, и никакого влияния на производительность запроса это не даст.
Возвращаясь к вопросу оптимизации - первый вариант быстрее. Но прийти к пониманию этого можно аж двумя способами:
1) заранее зная, какой механизм заложен в ту или иную функцию PQ и что она делает под ковром, и как работает внутренний оптимизатор PQ 2) методом проб и ошибок, тестирования, изучения документации, задавания вопросов, чтения форумов и блогов
Обычно наш метод второй (если кто-то из разработчиков не поделился сокровенным знанием). Те, кто пишет более-менее оптимальный код - миксуют оба метода. Так что все нормально, вопрошайте, только следите за корректностью примеров, и вам весьма воздастся.
Дополнительная оптимизация вам - постарайтесь понять, что и зачем сделано:
Код
let
table2renamed = Table.RenameColumns(Таблица2, {{"Груз", "Gruz"}}),
table2tiny = Table.SelectColumns(table2renamed, {"Gruz","Цена"}),
Источник = Table.Join(Таблица1, {"Груз"}, table2tiny, {"Gruz"}, JoinKind.LeftOuter),
AddNewColumn = Table.AddColumn(Источник, "CorrectedPrice", each List.First(List.Select({какоетовыражение,[Цена]}, each _ <> null))),
Removed = Table.RemoveColumns(AddNewColumn , {"Gruz", "Цена"}),
final = Table.RenameColumns(Removed, {{"CorrectedPrice", "Цена"}}),
in
final
Что-то у меня по времени не сходится. Ресурсы только жрет. И первый запрос , и второй достаточно быстро обновляются Сработало, скорее всего, это:
Цитата
Максим Зеленский написал: только в редакторе при разработке - ему нужно сгенерировать для вас предпросмотр состояния запроса на конкретный шаг и закэшировать его. При рабочем выполнении запроса ему плевать на предпросмотр
Михаил Л написал: Что-то у меня по времени не сходится
Проверяйте, код я выписал, фаил скачать от куда тоже написал. Не поленился сходил еще на одну машину с i5 на борту, запустил фаил с 1 млн строк, 16 секунд выполняет запрос 1 и 27 секунд выполняет запрос 2
PooHkrd написал: То, что описано в статье больше имеет отношение именно к редактору запросов
Господа, Вы сломали мои стереотипы. Спасибо. Не буду излишне нагромождать переменные.
Однако, честно, Вариант написанныйМаксим Зеленский, вторым для меня немного понятнее, я еще не знаю как работает List, и мне сложно понять что происходит тут,
Код
each List.First( List.Select(
но остальное вполне читаемо, особенно если влепить комментарии, по моему воспринимается проще, чем в голове держать несколько переменных. С другой стороны, если операторы не знаешь, как в моем случае с list, то конечно тыкалками натыкать и понять что происходит не получится.
Михаил Л написал: Что-то у меня по времени не сходится
Это относится к статье. В статье речь про два запроса, один из которых, якобы, обновляется долго. В файле есть эти запросы(укороченные). Оба запроса обновляются, на мой взгляд, недолго.
lostandleft, ещё один голос не в пользу большого количества вложенных функций это поиск багов. Рано или поздно в каком-то из источников кто-то что- подменяет и запрос выдаст ошибку. Поверьте искать ошибку в запросе с малой вложенностью значительно проще чем наоборот.