Как стать автором
Обновить
2
0
Roman Pekar @OrmEugensson

Пользователь

Отправить сообщение

Для постгреса пока удобного метода не нашёл (смотрю на FlyWay), для Sql Server используем https://www.red-gate.com/products/sql-development/sql-change-automation/. Он позволяет хранить миграционные скрипты + текущий снапшот схемы данных.

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

У меня есть практический вопрос. Предположим, у меня есть проект с бизнес логикой на MS SQL. Возможно ли 'вместо MS SQL' использовать lsFusion + PostgreSQL (только как бек енд сервер)?
справедливости ради надо сказать — сейчас 2019 год, с 2008R2 многое поменялось. Но вообще странно, да.
да, согласен, просто неверно прочитал «Например, есть HAVING, который полностью эквивалентен подзапросу и WHERE на подзапрос» — почему-то у менять осталось впечатление, что будет что-то вроде: where (select sum(salary) ...) > 100000

Не совсем согласен, что HAVING не нужен, но согласен, что функционально его можно заменить. Можете привести код на lsfusion или Вы не по этой части?
По поводу триггеров.

Я в основном работаю на Ms Sql и там никогда не было триггеров per row, триггеры только per statement. То есть в вашем конкретном случае в на один стейтмент один запуск триггера и в контексте триггера будут две таблицы inserted и deleted, которые будут содержать данные до и после апдейта (100 записей в каждой)
То есть для Ms Sql ответ будет — на один стейтмент один запуск триггера.

В Postgres как минимум в версии 11 уже были два варианта — можно объявить триггер per row а можно объявить триггер per statement. Соответственно, per statement работает так же, как и Ms Sql, а per row реально запустит триггер 100 раз.

Я не большой спец в Postgres поэтому не могу дать 100% гарантии что per row триггер не оптимизируется, но когда я около полугода назад это тестировал на 10000 записях, пустой per row триггер работал явно медленнее пустого per statement триггера.
Давайте так, тут по хорошему надо не запросами, а планами меряться. И в нашем и в вашем все будет хорошо, чудеса начнутся когда вы их материализовать захотите. Но в любом случае спор уже куда то не туда ушел.

да я не хотел меряться. Вы просто утверждаете, что lsfusion как язык программирования более выразителен для работы с данными, чем sql, а я с этим не согласен. Поэтому хотел увидеть, как в вашем случае выглядит пример такого запроса (элементарного в sql) и как будет выглядеть его модификация при необходимости.
да, абсолютно. Все селект запросы в sql это типичные функции без сайд эффектов.
Собственно, мы с моим коллегой вынашиваем идею языка-надстройки над sql который позволит так работать — передавать запросы как параметры в функции, возвращать запросы и т.д. Сейчас, в принципе, можно такое сделать через курсоры, но это сразу убивает всю set-based-thinking парадигму.
Как обычно, времени на это нет.

Пытаюсь внедрить эту идею в мозги разработчиков Postgres на митапах :) Потому что, насколько знаю, Postgresовская система типов лучшая среди всех RDBMS, было бы логично её расширить.
ну вот, а вы говорили оптимизатор Postgres глупый. Но все равно этот запрос не эквивалентен моему. Постараюсь объяснить
1. Мой первый запрос — группировка сотрудника по департаментам -> фильтр по результатам агрегации.
2. Мой второй запрос — фильтр сотрудников -> группировка по департаментам -> фильтр по результатам агрегации.
именно этого мне не хватает в стандарте sql — query as first class citizen.
спасибо, я абсолютно согласен с этим заявлением. Здесь это усугубляется тем, что предполагается, что на этой платформе разрабатывают бизнес пользователи, а не разработчики. Судя по опыту, бизнес пользователем уж точно всё равно что будет завтра с этими функциями, им надо сейчас сделать чтоб отчёт работал.
ваш последний пример, кстати, не эквивалентен моему запросу. И linq, как раз, именно в этом примере обыгрывает sql за счет комбинируемости. В sql я могу сделать так

select
    department_id,
    array_agg(id) as employees,
    sum(tax) as tax
from employee
group by
    department_id
having
    sum(salary) > 100000 and
    count(*) < 10 and
    count(distinct gender) = 2


а потом мне надо отфильтровать employee по каким-то критериям, мне придется править исходный запрос

select
    department_id,
    array_agg(id) as employees,
    sum(tax) as tax
from employee
where
    salary > 10000
group by
    department_id
having
    sum(salary) > 100000 and
    count(*) < 10 and
    count(distinct gender) = 2


и в sql я не могу сделать так, чтобы employee была переменной (я могу конечно сделать темп таблицу, и использовать её, но это перекладывание данных). А вот что я хотел бы уметь делать в sql


set @employee = (select * from employee);

--optional
set @employee = (select * from @employee where salary > 10000);

select
    department_id,
    array_agg(id) as employees,
    sum(tax) as tax
from @employee
group by
    department_id
having
    sum(salary) > 100000 and
    count(*) < 10 and
    count(distinct gender) = 2;


и linq как раз тут просто обыгрывает стандартный сиквел на порядки.
а всего-то надо сделать query first class citizen
Вот это очень странное утверждение. Я как бы тоже неплохо разбираюсь в запросах, но сказать на сто процентов какой запрос будет эффективнее без реального плана выполнения я не смогу. Более того, на разной статистике у разных запросов будут разные планы и, соответственно, разная эффективность.


я в данном случае говорю только об эквивалентности запроса, не об эффективности. То есть логика запроса должна быть одинаковая
немного переформатировал запрос, чтобы стало понятнее. Но где там фильтр по employee.salary > 10000?

with cte_employee as (
	select
		t0.Main_department_Employee as k0,
		t0.Main_gender_Employee as k1,
		notZero(count(*)) as e0
	from _auto_Main_Employee as t0
	where
		t0.Main_department_Employee is not null and
		t0.Main_gender_Employee is not null
    group by
		t0.Main_department_Employee,
		t0.Main_gender_Employee
), cte_employee_count as (
	select
		t0.k0 as k0,
		notZero(count(*)) as e0
	from cte_employee as t0
	where
		notZero(coalesce(t0.e0, 0)) is not null
	group by
		t0.k0
)
select
	t0.k0 as jkey0,
	t0.k0 as jprop0
from cte_employee_count as t0
	inner join (
		select
			t1.Main_department_Employee as k0,
			notZero(sum(t1.Main_salary_Employee)) as e0,
			notZero(count(*)) as e1
		from _auto_Main_Employee as t1
			inner join cte_employee_count as t0 on
				t0.k0 = t1.Main_department_Employee
		where
			t0.e0 = 2
		group by
			t1.Main_department_Employee
	) as t1 on
		t1.k0 = t0.k0
where
	(notZero(coalesce(t1.e0, 0)) > 100000) and
	(10 > notZero(coalesce(t1.e1, 0))) and
	t0.e0 = 2
Это утверждение ложно как минимум в MS SQL, в PostgreSQL насколько знаю тоже — если функция это чистый sql то она инлайнится.
я почти уверен что неэквивалентно (и, похоже, вы не понимаете, как работает having). Можете, пожалуйста, написать полный запрос на lsfusion и показать в какой sql он трансформируется в вашей платформе.
Не надо мне рассказывать про проблему оптимизации sql запроса, просто напишите этот запрос и покажите sql который получается в результате. Тогда я смогу оценить, эквивалентно оно или нет.
Я понимаю, что ваша платформа позволяет писать стандартные формы очень быстро, и это хорошее и, похоже, нужное вам свойство, но вы также утверждаете, что язык более выразителен чем sql, и с этим я совершенно не согласен.
ну вообще-то в тех RDBMS в которых я работал (MS SQL в основном, но вроде в постгресе тоже), можно определять табличные функции, так что ничего копипастить не надо
если я правильно понимаю как оно у вас работает это не эквивалентно запросу выше. Либо N надо передать во все функции либо у вас там какой-то искуственный интеллект
если это мне вопрос, то не понял вопроса
я наверное плохо объясняю. Вот такое как сделать

select
    department_id,
    array_agg(id) as employees,
    sum(tax) as tax
from employee
where
     salary > 10000
group by
    department_id
having
    sum(salary) > 100000 and
    count(*) < 10 and
    count(distinct gender) = 2
что если требования такие — только в одном месте должен появиться фильтр по зарплате, в остальных местах все остаётся как прежде?

Пусть так — можете написать вариант кода который позволит сымитировать поведение такой функции:

select
    department_id,
    array_agg(id) as employees,
    sum(tax) as tax
from employee
where
     salary between [param1] and [param2]
group by
    department_id
having
    sum(salary) > [param3] and
    count(*) < 10 and
    count(distinct gender) = 2

Информация

В рейтинге
Не участвует
Зарегистрирован
Активность