Сообщение Re[6]: Проблемы современных СУБД от 20.02.2018 10:35
Изменено 20.02.2018 10:50 vdimas
Re[6]: Проблемы современных СУБД
Здравствуйте, gandjustas, Вы писали:
V>>В 100% случаев "возможности метапрограммирования" в статических языках используются для другого — для compile-time выбора специфической реализации для специфических типов. Такое "вычисление" порой само является достаточно сложной программой, но её нет в бинарнике.
G>Это только в одном языке
Ключевое выделил.
Таких языков в достатке, помимо того языка, о котором ты подумал и про который забыл — D.
Любой функциональный с системой типов не слабее чем у Хаскеля — туда же.
Информация о типах в рантайме стирается, поэтому, в распоряжении лишь система типов времени компиляции.
(информация к размышлению: в С++ и в Хаскеле прямо сейчас вовсю работают над метаинформацией времени компиляции)
V>>Для конкретной компиллируемой программы выводимый тип кортежа всегда известен.
G>Ага, выпиши его на Java например.
А почему не Скала с её case-classes?
Тем более, что предлагалось пофантазировать насчёт того, каким этот гипотетический язык мог быть и как повлияли бы его фичи на сценарии вокруг работы с данными.
V>>И вообще любой язык с реализованными в нём замыканиями.
V>>Только и это не обязательная фишка, а лишь бонусная к удобству, можно и без замыканий.
G>Ок, покажи пример.
G>Нам же не надо генерировать sql на выходе. Достаточно в системе типов языка описать выражения РА или SQL.
Ну вот, уже сам спрашиваешь, сам правильно отвечаешь. ))
G>Например как на любом предложенном тобой языке будет выглядеть аналог следующего кода:
G>
Да как угодно вплоть до того же, что так же — это в терминах РИ.
Или можно расписать в терминах РА на каком-нить ML-подобном слегка допиленном языке:
Какие-то вещи удобней расписывать в РИ, какие-то в РА.
Ожидаемо, что в случае перекрёстных параметров м/у ровнями вложенности удобней РИ (и то не всегда).
В любом случае для компилятора эти представления выглядят тождественно, он в любом случае внутри оперирует системой уравнений РА при построении планов запроса.
Но!
В случае РА можно говорить о привычном библиотечном подходе, т.е. для своей системы можно определить прикладные "кубики" и собирать запросы из них. В то время как РИ будет прибито гвоздями к конкретным таблицам.
Обрати внимание, что в моём варианте на РА используется параметрический полиморфизм.
Т.е. мало того, что в "библиотечные" запросы можно подавать таблицы, подходящие по типу, но сам тип таблицы и типы её полей могут быть "генериком".
_>>>>Причём для этого в языке совершенно не требуется наличия той рефлексия-подобной штуки, которую подразумевал тут ты.
G>>>Рефлексия в каком-то виде все равно будет.
V>>Разве что в compile-time.
V>>В бинарнике типы стираются.
G>А зачем? Чтобы себе же усложнить жизнь при генерации запроса в базу?
Вооот.
Это почему я поставил сплошные руки-лица в ответ на первое твоё сообщение в этой ветке.
Тебе удалось довольно-таки хорошо раскрыть некий вариант устройства подобной системы, как и самостоятельно увидеть отсутствие бенефитов такого варианта. Получилось эдакое самообслуживание — мне даже отвечать не надо было, ты и сам с собой неплохо пообщался. ))
Фишка предлагаемого мною в том, что вот этот компилятор над описанным выражением — это и есть СУБД.
Т.е. этот язык компиллируется там же, где и современный SQL, разве что не в динамике, а в статике.
Т.е. никаких других "запросов" к базе, кроме вот этого исходника типизированного кода, нет.
На выходе бинарь, который работает в процессе СУБД.
Прикладная часть бинаря общается примерно с тем же слоем низлежащего движка СУБД, с которым общается "исполнитель запросов" в нынешнем традиционном варианте.
G>Или ты реально думаешь что все запросы в программе будут статичными, а не генерироваться на основе входных параметров?
Ну, если запретить рекурсию с неизвестной вложенностью при составлении запроса из "кубиков", то компилятор выведет всё мн-во запросов над конкретными таблицами.
В случае же простого комбинирования "кубиков" — тем более.
Т.е. достаточно, чтобы рекурсия/цикл процедуры генерации запроса были с известным на момент компиляции кол-вом повторений — и можно генерить запросы весьма развесисто — пофик. Я гонял современный С++, задавал ему развесистую рекурсию при выведении типа из шаблона с глубиной в несколько тысяч уровней — аппетитно ест и даже причмокивает. "На ноутбуке с батарейкой". (С)
Таблицы базы могут быть представлены некими "ниспосланными свыше" глобальными переменными программы (объявлены как глобальные переменные).
Вот от этих глобальных таблиц и пляшем, подставляя их в свои "запросы" — а на самом деле просто в некий код, где тебе не надо будет сильно отличать обычный код над списками/хеш-таблицами в оперативке или в БД. И одни и те же запросы, разумеется, будут работать как над переменными в памяти, так и над данными на диске, бо параметрический полиморфизм "унутре" почти всегда превращается в ad-hoc в процессе бета-редукции. "Одни и те же" в смысле только лишь исходного кода, разумеется.
Еще соображения.
На стороне СУБД очень мало функциональности.
Т.е. много таблиц, много запросов, много хранимок, но уникальной функциональности кот наплакал. Для обычного современного мейнстримового языка — просто тьфу. Так вот, хороший язык должен позволять быстро убегать от дублирования кода, т.е. должен в разы удешевлять разработку и поддержку.
G>>>Ты же не сможешь проверить корректность дерева выражения относительно sql если не имеешь в дереве выражений информацию о типе.
V>>В рантайм этого и не требуется, если компилятор обеспечивает строгую статическую типизацию.
G>Ты походу не очень понимаешь о чем пишешь.
G>Что будет на выходе компилятора?
На выходе компилятора будет готовое упорядоченное мн-во планов запросов и готовый оптимизированный код оценки каждого плана.
Тут рядом я несколько раз выскзывался в сообщениях, что сами планы запросов можно хранить весьма компактно — это же просто дерево перебора вариантов, где многие перебираемые ветки/листья дерева будут идентичными у многих запросов. Более того, это дерево можно хранить не в виде данных а в виде рекурсивных процедур обхода. Обход там нужен исключительно и только чтобы грубо прикинуть оценку стоимости запроса по каждому из плану и выбрать лучший из них (или достаточно хороший).
Там еще мелочей хватает, я уже рядом расписывал и вообще, тут интересней, ИМХО, вообразить самим. ))
G>Готовый SQL или любой аналог?
Вот то, что мы писали — это и есть наш "новый SQL", т.е. его аналог.
Просто хотелось убежать от динамики и многословности.
Далее.
Для клиента такой СУБД проектируется некий публичный интерфейс (отмечаем нужное извне как public), и после компиляции получается артефакт —
некая библиотека типов. В виде текстового IDL или какого-нить бинарного формата, типа Typelib.
Далее из этой библиотеки типов можно сгенерить готовую для линковку библиотеку, которая будет брать транспортные вопросы на себя, т.е. будет брать на себя ф-ии DAL целиком. Итого, простор для ошибок несогласованности клиента и сервера уменьшается.
G>Если у тебя запрос генерируется на основе входных параметров, то что?
... то компилятор "видит" как такой запрос генерируется.
Или ты говоришь о простом параметре-константе в каком-нить предикате (навроде select * from users where id = concrete_id)?
Этот сценарий даже обсуждать облом, тут всё ясно.
А вот первый вариант может даже дать некий комбинаторный взрыв, угу.
Предлагаю его оценить по реальным своим проектам.
Я оценивал — фигня полная.
Ну, т.е. лишнего бинарного кода будет сегерён с гулькин нос по нынешним меркам (5-6 мег на все "взрывы", где самих "врывов" даже в большой системе весьма счётное кол-во — единицы/десятки, остальное всё прекрасно обходится без взрывов, чиста через параметры хранимок).
V>>В современном С++ можно что-то типа такого:
...
G>Уверен? Как выражение x.StartDate.Date + x.Duration / 24 превратится в часть запроса?
Превратится на этапе компиляции из некоего своего AST.
Лямбда — это ж полноправная единица языка, что не так?
G>Какие типы будут у t, x и его свойств, возвращаемого значения?
Я переводил твой пример. А у тебя t задаётся "где-то еще".
Остальные типы просто выводятся современным С++.
V>>Гуглить "named tuple", это довольно популярное игрище.
V>>https://github.com/duckie/named_types/tree/master/test
V>>http://vitiy.info/named-tuple-for-cplusplus/
V>>В "более функциональном" языке можно было с более простым синтаксисом лямбды сделать...
G>Это как бы в теории
Почему в теории? В том же Хаскеле синтаксис лямбды весьма лаконичен.
Но даже и этот синтаксис можно упростить до (ты правильно говорил) простого цитирования.
Просто я возражал насчёт прям-таки обязательности наличия цитирования.
В моём примере выше можно заменить лямбды на ф-ии и всё останется работоспособным, просто будет менее удобным.
Честно говоря — и тот код неудобен, можно было поинересней нарисовать.
Просто не хотелось сходу гнать совсем уж отсебятину, лучше двигаться поэтапно — смотреть что уже есть, чего не хватает, что мешает и почему.
В общем, обсуждаемое тут — это в том числе вопросы удобства "нового SQL" в сравнении чем-то нынешним.
А раз так, то нельзя "запрещать" мне желать любые теоретически-возможные вкусняшки.
(остальное потом)
V>>В 100% случаев "возможности метапрограммирования" в статических языках используются для другого — для compile-time выбора специфической реализации для специфических типов. Такое "вычисление" порой само является достаточно сложной программой, но её нет в бинарнике.
G>Это только в одном языке
Ключевое выделил.
Таких языков в достатке, помимо того языка, о котором ты подумал и про который забыл — D.
Любой функциональный с системой типов не слабее чем у Хаскеля — туда же.
Информация о типах в рантайме стирается, поэтому, в распоряжении лишь система типов времени компиляции.
(информация к размышлению: в С++ и в Хаскеле прямо сейчас вовсю работают над метаинформацией времени компиляции)
V>>Для конкретной компиллируемой программы выводимый тип кортежа всегда известен.
G>Ага, выпиши его на Java например.
А почему не Скала с её case-classes?
Тем более, что предлагалось пофантазировать насчёт того, каким этот гипотетический язык мог быть и как повлияли бы его фичи на сценарии вокруг работы с данными.
V>>И вообще любой язык с реализованными в нём замыканиями.
V>>Только и это не обязательная фишка, а лишь бонусная к удобству, можно и без замыканий.
G>Ок, покажи пример.
G>Нам же не надо генерировать sql на выходе. Достаточно в системе типов языка описать выражения РА или SQL.
Ну вот, уже сам спрашиваешь, сам правильно отвечаешь. ))
G>Например как на любом предложенном тобой языке будет выглядеть аналог следующего кода:
G>
G>select t.x, (select sum (tt.x) from t tt where tt.x <> (t.x+1))
G>from t
G>
Да как угодно вплоть до того же, что так же — это в терминах РИ.
Или можно расписать в терминах РА на каком-нить ML-подобном слегка допиленном языке:
Data Result t {X:t.x, Y:t.x};
MyCoolQuery t :: [t -> x] -> [Result]
MyCoolQuery t = do {
tt_row t x = fold sum $ filter (r -> r.x /= x+1) t;
t_row t x = Result {x, tt_row t x};
return $ map t (x -> t_row t x);
}
Какие-то вещи удобней расписывать в РИ, какие-то в РА.
Ожидаемо, что в случае перекрёстных параметров м/у ровнями вложенности удобней РИ (и то не всегда).
В любом случае для компилятора эти представления выглядят тождественно, он в любом случае внутри оперирует системой уравнений РА при построении планов запроса.
Но!
В случае РА можно говорить о привычном библиотечном подходе, т.е. для своей системы можно определить прикладные "кубики" и собирать запросы из них. В то время как РИ будет прибито гвоздями к конкретным таблицам.
Обрати внимание, что в моём варианте на РА используется параметрический полиморфизм.
Т.е. мало того, что в "библиотечные" запросы можно подавать таблицы, подходящие по типу, но сам тип таблицы и типы её полей могут быть "генериком".
_>>>>Причём для этого в языке совершенно не требуется наличия той рефлексия-подобной штуки, которую подразумевал тут ты.
G>>>Рефлексия в каком-то виде все равно будет.
V>>Разве что в compile-time.
V>>В бинарнике типы стираются.
G>А зачем? Чтобы себе же усложнить жизнь при генерации запроса в базу?
Вооот.
Это почему я поставил сплошные руки-лица в ответ на первое твоё сообщение в этой ветке.
Тебе удалось довольно-таки хорошо раскрыть некий вариант устройства подобной системы, как и самостоятельно увидеть отсутствие бенефитов такого варианта. Получилось эдакое самообслуживание — мне даже отвечать не надо было, ты и сам с собой неплохо пообщался. ))
Фишка предлагаемого мною в том, что вот этот компилятор над описанным выражением — это и есть СУБД.
Т.е. этот язык компиллируется там же, где и современный SQL, разве что не в динамике, а в статике.
Т.е. никаких других "запросов" к базе, кроме вот этого исходника типизированного кода, нет.
На выходе бинарь, который работает в процессе СУБД.
Прикладная часть бинаря общается примерно с тем же слоем низлежащего движка СУБД, с которым общается "исполнитель запросов" в нынешнем традиционном варианте.
G>Или ты реально думаешь что все запросы в программе будут статичными, а не генерироваться на основе входных параметров?
Ну, если запретить рекурсию с неизвестной вложенностью при составлении запроса из "кубиков", то компилятор выведет всё мн-во запросов над конкретными таблицами.
В случае же простого комбинирования "кубиков" — тем более.
Т.е. достаточно, чтобы рекурсия/цикл процедуры генерации запроса были с известным на момент компиляции кол-вом повторений — и можно генерить запросы весьма развесисто — пофик. Я гонял современный С++, задавал ему развесистую рекурсию при выведении типа из шаблона с глубиной в несколько тысяч уровней — аппетитно ест и даже причмокивает. "На ноутбуке с батарейкой". (С)
Таблицы базы могут быть представлены некими "ниспосланными свыше" глобальными переменными программы (объявлены как глобальные переменные).
Вот от этих глобальных таблиц и пляшем, подставляя их в свои "запросы" — а на самом деле просто в некий код, где тебе не надо будет сильно отличать обычный код над списками/хеш-таблицами в оперативке или в БД. И одни и те же запросы, разумеется, будут работать как над переменными в памяти, так и над данными на диске, бо параметрический полиморфизм "унутре" почти всегда превращается в ad-hoc в процессе бета-редукции. "Одни и те же" в смысле только лишь исходного кода, разумеется.
Еще соображения.
На стороне СУБД очень мало функциональности.
Т.е. много таблиц, много запросов, много хранимок, но уникальной функциональности кот наплакал. Для обычного современного мейнстримового языка — просто тьфу. Так вот, хороший язык должен позволять быстро убегать от дублирования кода, т.е. должен в разы удешевлять разработку и поддержку.
G>>>Ты же не сможешь проверить корректность дерева выражения относительно sql если не имеешь в дереве выражений информацию о типе.
V>>В рантайм этого и не требуется, если компилятор обеспечивает строгую статическую типизацию.
G>Ты походу не очень понимаешь о чем пишешь.
G>Что будет на выходе компилятора?
На выходе компилятора будет готовое упорядоченное мн-во планов запросов и готовый оптимизированный код оценки каждого плана.
Тут рядом я несколько раз выскзывался в сообщениях, что сами планы запросов можно хранить весьма компактно — это же просто дерево перебора вариантов, где многие перебираемые ветки/листья дерева будут идентичными у многих запросов. Более того, это дерево можно хранить не в виде данных а в виде рекурсивных процедур обхода. Обход там нужен исключительно и только чтобы грубо прикинуть оценку стоимости запроса по каждому из плану и выбрать лучший из них (или достаточно хороший).
Там еще мелочей хватает, я уже рядом расписывал и вообще, тут интересней, ИМХО, вообразить самим. ))
G>Готовый SQL или любой аналог?
Вот то, что мы писали — это и есть наш "новый SQL", т.е. его аналог.
Просто хотелось убежать от динамики и многословности.
Далее.
Для клиента такой СУБД проектируется некий публичный интерфейс (отмечаем нужное извне как public), и после компиляции получается артефакт —
некая библиотека типов. В виде текстового IDL или какого-нить бинарного формата, типа Typelib.
Далее из этой библиотеки типов можно сгенерить готовую для линковку библиотеку, которая будет брать транспортные вопросы на себя, т.е. будет брать на себя ф-ии DAL целиком. Итого, простор для ошибок несогласованности клиента и сервера уменьшается.
G>Если у тебя запрос генерируется на основе входных параметров, то что?
... то компилятор "видит" как такой запрос генерируется.
Или ты говоришь о простом параметре-константе в каком-нить предикате (навроде select * from users where id = concrete_id)?
Этот сценарий даже обсуждать облом, тут всё ясно.
А вот первый вариант может даже дать некий комбинаторный взрыв, угу.
Предлагаю его оценить по реальным своим проектам.
Я оценивал — фигня полная.
Ну, т.е. лишнего бинарного кода будет сегерён с гулькин нос по нынешним меркам (5-6 мег на все "взрывы", где самих "врывов" даже в большой системе весьма счётное кол-во — единицы/десятки, остальное всё прекрасно обходится без взрывов, чиста через параметры хранимок).
V>>В современном С++ можно что-то типа такого:
...
G>Уверен? Как выражение x.StartDate.Date + x.Duration / 24 превратится в часть запроса?
Превратится на этапе компиляции из некоего своего AST.
Лямбда — это ж полноправная единица языка, что не так?
G>Какие типы будут у t, x и его свойств, возвращаемого значения?
Я переводил твой пример. А у тебя t задаётся "где-то еще".
Остальные типы просто выводятся современным С++.
V>>Гуглить "named tuple", это довольно популярное игрище.
V>>https://github.com/duckie/named_types/tree/master/test
V>>http://vitiy.info/named-tuple-for-cplusplus/
V>>В "более функциональном" языке можно было с более простым синтаксисом лямбды сделать...
G>Это как бы в теории
Почему в теории? В том же Хаскеле синтаксис лямбды весьма лаконичен.
Но даже и этот синтаксис можно упростить до (ты правильно говорил) простого цитирования.
Просто я возражал насчёт прям-таки обязательности наличия цитирования.
В моём примере выше можно заменить лямбды на ф-ии и всё останется работоспособным, просто будет менее удобным.
Честно говоря — и тот код неудобен, можно было поинересней нарисовать.
Просто не хотелось сходу гнать совсем уж отсебятину, лучше двигаться поэтапно — смотреть что уже есть, чего не хватает, что мешает и почему.
В общем, обсуждаемое тут — это в том числе вопросы удобства "нового SQL" в сравнении чем-то нынешним.
А раз так, то нельзя "запрещать" мне желать любые теоретически-возможные вкусняшки.
(остальное потом)
Re[6]: Проблемы современных СУБД
Здравствуйте, gandjustas, Вы писали:
V>>В 100% случаев "возможности метапрограммирования" в статических языках используются для другого — для compile-time выбора специфической реализации для специфических типов. Такое "вычисление" порой само является достаточно сложной программой, но её нет в бинарнике.
G>Это только в одном языке
Ключевое выделил.
Таких языков в достатке, помимо того языка, о котором ты подумал и про который забыл — D.
Любой функциональный с системой типов не слабее чем у Хаскеля — туда же.
Информация о типах в рантайме стирается, поэтому, в распоряжении лишь система типов времени компиляции.
(информация к размышлению: в С++ и в Хаскеле прямо сейчас вовсю работают над метаинформацией времени компиляции)
V>>Для конкретной компиллируемой программы выводимый тип кортежа всегда известен.
G>Ага, выпиши его на Java например.
А почему не Скала с её case-classes?
Тем более, что предлагалось пофантазировать насчёт того, каким этот гипотетический язык мог быть и как повлияли бы его фичи на сценарии вокруг работы с данными.
V>>И вообще любой язык с реализованными в нём замыканиями.
V>>Только и это не обязательная фишка, а лишь бонусная к удобству, можно и без замыканий.
G>Ок, покажи пример.
G>Нам же не надо генерировать sql на выходе. Достаточно в системе типов языка описать выражения РА или SQL.
Ну вот, уже сам спрашиваешь, сам правильно отвечаешь. ))
G>Например как на любом предложенном тобой языке будет выглядеть аналог следующего кода:
G>
Да как угодно вплоть до того же, что так же — это в терминах РИ.
Или можно расписать в терминах РА на каком-нить ML-подобном слегка допиленном языке:
Какие-то вещи удобней расписывать в РИ, какие-то в РА.
Ожидаемо, что в случае перекрёстных параметров м/у ровнями вложенности удобней РИ (и то не всегда).
В любом случае для компилятора эти представления выглядят тождественно, он в любом случае внутри оперирует системой уравнений РА при построении планов запроса.
Но!
В случае РА можно говорить о привычном библиотечном подходе, т.е. для своей системы можно определить прикладные "кубики" и собирать запросы из них. В то время как РИ будет прибито гвоздями к конкретным таблицам.
Обрати внимание, что в моём варианте на РА используется параметрический полиморфизм.
Т.е. мало того, что в "библиотечные" запросы можно подавать таблицы, подходящие по типу, но сам тип таблицы и типы её полей могут быть "генериком".
_>>>>Причём для этого в языке совершенно не требуется наличия той рефлексия-подобной штуки, которую подразумевал тут ты.
G>>>Рефлексия в каком-то виде все равно будет.
V>>Разве что в compile-time.
V>>В бинарнике типы стираются.
G>А зачем? Чтобы себе же усложнить жизнь при генерации запроса в базу?
Вооот.
Это почему я поставил сплошные руки-лица в ответ на первое твоё сообщение в этой ветке.
Тебе удалось довольно-таки хорошо раскрыть некий вариант устройства подобной системы, как и самостоятельно увидеть отсутствие бенефитов такого варианта. Получилось эдакое самообслуживание — мне даже отвечать не надо было, ты и сам с собой неплохо пообщался. ))
Фишка предлагаемого мною в том, что вот этот компилятор над описанным выражением — это и есть СУБД.
Т.е. этот язык компиллируется там же, где и современный SQL, разве что не в динамике, а в статике.
Т.е. никаких других "запросов" к базе, кроме вот этого исходника типизированного кода, нет.
На выходе бинарь, который работает в процессе СУБД.
Прикладная часть бинаря общается примерно с тем же слоем низлежащего движка СУБД, с которым общается "исполнитель запросов" в нынешнем традиционном варианте.
G>Или ты реально думаешь что все запросы в программе будут статичными, а не генерироваться на основе входных параметров?
Ну, если запретить рекурсию с неизвестной вложенностью при составлении запроса из "кубиков", то компилятор выведет всё мн-во запросов над конкретными таблицами.
В случае же простого комбинирования "кубиков" — тем более.
Т.е. достаточно, чтобы рекурсия/цикл процедуры генерации запроса были с известным на момент компиляции кол-вом повторений — и можно генерить запросы весьма развесисто — пофик. Я гонял современный С++, задавал ему развесистую рекурсию при выведении типа из шаблона с глубиной в несколько тысяч уровней — аппетитно ест и даже причмокивает. "На ноутбуке с батарейкой". (С)
Таблицы базы могут быть представлены некими "ниспосланными свыше" глобальными переменными программы (объявлены как глобальные переменные).
Вот от этих глобальных таблиц и пляшем, подставляя их в свои "запросы" — а на самом деле просто в некий код, где тебе не надо будет сильно отличать обычный код над списками/хеш-таблицами в оперативке или в БД. И одни и те же запросы, разумеется, будут работать как над переменными в памяти, так и над данными на диске, бо параметрический полиморфизм "унутре" почти всегда превращается в ad-hoc в процессе бета-редукции. "Одни и те же" в смысле только лишь исходного кода, разумеется.
Еще соображения.
На стороне СУБД очень мало функциональности.
Т.е. много таблиц, много запросов, много хранимок, но уникальной функциональности кот наплакал. Для обычного современного мейнстримового языка — просто тьфу. Так вот, хороший язык должен позволять быстро убегать от дублирования кода, т.е. должен в разы удешевлять разработку и поддержку.
G>>>Ты же не сможешь проверить корректность дерева выражения относительно sql если не имеешь в дереве выражений информацию о типе.
V>>В рантайм этого и не требуется, если компилятор обеспечивает строгую статическую типизацию.
G>Ты походу не очень понимаешь о чем пишешь.
G>Что будет на выходе компилятора?
На выходе компилятора будет готовое упорядоченное мн-во планов запросов и готовый оптимизированный код оценки каждого плана.
Тут рядом я несколько раз выскзывался в сообщениях, что сами планы запросов можно хранить весьма компактно — это же просто дерево перебора вариантов, где многие перебираемые ветки/листья дерева будут идентичными у многих запросов. Более того, это дерево можно хранить не в виде данных а в виде рекурсивных процедур обхода. Обход там нужен исключительно и только чтобы грубо прикинуть оценку стоимости запроса по каждому из плану и выбрать лучший из них (или достаточно хороший).
Там еще мелочей хватает, я уже рядом расписывал и вообще, тут интересней, ИМХО, вообразить самим. ))
G>Готовый SQL или любой аналог?
Вот то, что мы писали — это и есть наш "новый SQL", т.е. его аналог.
Просто хотелось убежать от динамики и многословности.
Далее.
Для клиента такой СУБД проектируется некий публичный интерфейс (отмечаем нужное извне как public), и после компиляции получается артефакт —
некая библиотека типов. В виде текстового IDL или какого-нить бинарного формата, типа Typelib.
Далее из этой библиотеки типов можно сгенерить готовую для линковку клиентскую библиотеку, которая будет брать транспортные вопросы на себя, т.е. будет брать на себя ф-ии DAL целиком. Итого, простор для ошибок несогласованности клиента и сервера уменьшается.
G>Если у тебя запрос генерируется на основе входных параметров, то что?
... то компилятор "видит" как такой запрос генерируется.
Или ты говоришь о простом параметре-константе в каком-нить предикате (навроде select * from users where id = concrete_id)?
Этот сценарий даже обсуждать облом, тут всё ясно.
А вот первый вариант может даже дать некий комбинаторный взрыв, угу.
Предлагаю его оценить по реальным своим проектам.
Я оценивал — фигня полная.
Ну, т.е. лишнего бинарного кода будет сегерён с гулькин нос по нынешним меркам (5-6 мег на все "взрывы", где самих "врывов" даже в большой системе весьма счётное кол-во — единицы/десятки, остальное всё прекрасно обходится без взрывов, чиста через параметры хранимок).
V>>В современном С++ можно что-то типа такого:
...
G>Уверен? Как выражение x.StartDate.Date + x.Duration / 24 превратится в часть запроса?
Превратится на этапе компиляции из некоего своего AST.
Лямбда — это ж полноправная единица языка, что не так?
G>Какие типы будут у t, x и его свойств, возвращаемого значения?
Я переводил твой пример. А у тебя t задаётся "где-то еще".
Остальные типы просто выводятся современным С++.
V>>Гуглить "named tuple", это довольно популярное игрище.
V>>https://github.com/duckie/named_types/tree/master/test
V>>http://vitiy.info/named-tuple-for-cplusplus/
V>>В "более функциональном" языке можно было с более простым синтаксисом лямбды сделать...
G>Это как бы в теории
Почему в теории? В том же Хаскеле синтаксис лямбды весьма лаконичен.
Но даже и этот синтаксис можно упростить до (ты правильно говорил) простого цитирования.
Просто я возражал насчёт прям-таки обязательности наличия цитирования.
В моём примере выше можно заменить лямбды на ф-ии и всё останется работоспособным, просто будет менее удобным.
Честно говоря — и тот код неудобен, можно было поинересней нарисовать.
Просто не хотелось сходу гнать совсем уж отсебятину, лучше двигаться поэтапно — смотреть что уже есть, чего не хватает, что мешает и почему.
В общем, обсуждаемое тут — это в том числе вопросы удобства "нового SQL" в сравнении чем-то нынешним.
А раз так, то нельзя "запрещать" мне желать любые теоретически-возможные вкусняшки.
(остальное потом)
V>>В 100% случаев "возможности метапрограммирования" в статических языках используются для другого — для compile-time выбора специфической реализации для специфических типов. Такое "вычисление" порой само является достаточно сложной программой, но её нет в бинарнике.
G>Это только в одном языке
Ключевое выделил.
Таких языков в достатке, помимо того языка, о котором ты подумал и про который забыл — D.
Любой функциональный с системой типов не слабее чем у Хаскеля — туда же.
Информация о типах в рантайме стирается, поэтому, в распоряжении лишь система типов времени компиляции.
(информация к размышлению: в С++ и в Хаскеле прямо сейчас вовсю работают над метаинформацией времени компиляции)
V>>Для конкретной компиллируемой программы выводимый тип кортежа всегда известен.
G>Ага, выпиши его на Java например.
А почему не Скала с её case-classes?
Тем более, что предлагалось пофантазировать насчёт того, каким этот гипотетический язык мог быть и как повлияли бы его фичи на сценарии вокруг работы с данными.
V>>И вообще любой язык с реализованными в нём замыканиями.
V>>Только и это не обязательная фишка, а лишь бонусная к удобству, можно и без замыканий.
G>Ок, покажи пример.
G>Нам же не надо генерировать sql на выходе. Достаточно в системе типов языка описать выражения РА или SQL.
Ну вот, уже сам спрашиваешь, сам правильно отвечаешь. ))
G>Например как на любом предложенном тобой языке будет выглядеть аналог следующего кода:
G>
G>select t.x, (select sum (tt.x) from t tt where tt.x <> (t.x+1))
G>from t
G>
Да как угодно вплоть до того же, что так же — это в терминах РИ.
Или можно расписать в терминах РА на каком-нить ML-подобном слегка допиленном языке:
Data Result t {X:t.x, Y:t.x};
MyCoolQuery t :: [t -> x] -> [Result]
MyCoolQuery t = do {
tt_row t x = fold sum $ filter (r -> r.x /= x+1) t;
t_row t x = Result {x, tt_row t x};
return $ map t (x -> t_row t x);
}
Какие-то вещи удобней расписывать в РИ, какие-то в РА.
Ожидаемо, что в случае перекрёстных параметров м/у ровнями вложенности удобней РИ (и то не всегда).
В любом случае для компилятора эти представления выглядят тождественно, он в любом случае внутри оперирует системой уравнений РА при построении планов запроса.
Но!
В случае РА можно говорить о привычном библиотечном подходе, т.е. для своей системы можно определить прикладные "кубики" и собирать запросы из них. В то время как РИ будет прибито гвоздями к конкретным таблицам.
Обрати внимание, что в моём варианте на РА используется параметрический полиморфизм.
Т.е. мало того, что в "библиотечные" запросы можно подавать таблицы, подходящие по типу, но сам тип таблицы и типы её полей могут быть "генериком".
_>>>>Причём для этого в языке совершенно не требуется наличия той рефлексия-подобной штуки, которую подразумевал тут ты.
G>>>Рефлексия в каком-то виде все равно будет.
V>>Разве что в compile-time.
V>>В бинарнике типы стираются.
G>А зачем? Чтобы себе же усложнить жизнь при генерации запроса в базу?
Вооот.
Это почему я поставил сплошные руки-лица в ответ на первое твоё сообщение в этой ветке.
Тебе удалось довольно-таки хорошо раскрыть некий вариант устройства подобной системы, как и самостоятельно увидеть отсутствие бенефитов такого варианта. Получилось эдакое самообслуживание — мне даже отвечать не надо было, ты и сам с собой неплохо пообщался. ))
Фишка предлагаемого мною в том, что вот этот компилятор над описанным выражением — это и есть СУБД.
Т.е. этот язык компиллируется там же, где и современный SQL, разве что не в динамике, а в статике.
Т.е. никаких других "запросов" к базе, кроме вот этого исходника типизированного кода, нет.
На выходе бинарь, который работает в процессе СУБД.
Прикладная часть бинаря общается примерно с тем же слоем низлежащего движка СУБД, с которым общается "исполнитель запросов" в нынешнем традиционном варианте.
G>Или ты реально думаешь что все запросы в программе будут статичными, а не генерироваться на основе входных параметров?
Ну, если запретить рекурсию с неизвестной вложенностью при составлении запроса из "кубиков", то компилятор выведет всё мн-во запросов над конкретными таблицами.
В случае же простого комбинирования "кубиков" — тем более.
Т.е. достаточно, чтобы рекурсия/цикл процедуры генерации запроса были с известным на момент компиляции кол-вом повторений — и можно генерить запросы весьма развесисто — пофик. Я гонял современный С++, задавал ему развесистую рекурсию при выведении типа из шаблона с глубиной в несколько тысяч уровней — аппетитно ест и даже причмокивает. "На ноутбуке с батарейкой". (С)
Таблицы базы могут быть представлены некими "ниспосланными свыше" глобальными переменными программы (объявлены как глобальные переменные).
Вот от этих глобальных таблиц и пляшем, подставляя их в свои "запросы" — а на самом деле просто в некий код, где тебе не надо будет сильно отличать обычный код над списками/хеш-таблицами в оперативке или в БД. И одни и те же запросы, разумеется, будут работать как над переменными в памяти, так и над данными на диске, бо параметрический полиморфизм "унутре" почти всегда превращается в ad-hoc в процессе бета-редукции. "Одни и те же" в смысле только лишь исходного кода, разумеется.
Еще соображения.
На стороне СУБД очень мало функциональности.
Т.е. много таблиц, много запросов, много хранимок, но уникальной функциональности кот наплакал. Для обычного современного мейнстримового языка — просто тьфу. Так вот, хороший язык должен позволять быстро убегать от дублирования кода, т.е. должен в разы удешевлять разработку и поддержку.
G>>>Ты же не сможешь проверить корректность дерева выражения относительно sql если не имеешь в дереве выражений информацию о типе.
V>>В рантайм этого и не требуется, если компилятор обеспечивает строгую статическую типизацию.
G>Ты походу не очень понимаешь о чем пишешь.
G>Что будет на выходе компилятора?
На выходе компилятора будет готовое упорядоченное мн-во планов запросов и готовый оптимизированный код оценки каждого плана.
Тут рядом я несколько раз выскзывался в сообщениях, что сами планы запросов можно хранить весьма компактно — это же просто дерево перебора вариантов, где многие перебираемые ветки/листья дерева будут идентичными у многих запросов. Более того, это дерево можно хранить не в виде данных а в виде рекурсивных процедур обхода. Обход там нужен исключительно и только чтобы грубо прикинуть оценку стоимости запроса по каждому из плану и выбрать лучший из них (или достаточно хороший).
Там еще мелочей хватает, я уже рядом расписывал и вообще, тут интересней, ИМХО, вообразить самим. ))
G>Готовый SQL или любой аналог?
Вот то, что мы писали — это и есть наш "новый SQL", т.е. его аналог.
Просто хотелось убежать от динамики и многословности.
Далее.
Для клиента такой СУБД проектируется некий публичный интерфейс (отмечаем нужное извне как public), и после компиляции получается артефакт —
некая библиотека типов. В виде текстового IDL или какого-нить бинарного формата, типа Typelib.
Далее из этой библиотеки типов можно сгенерить готовую для линковку клиентскую библиотеку, которая будет брать транспортные вопросы на себя, т.е. будет брать на себя ф-ии DAL целиком. Итого, простор для ошибок несогласованности клиента и сервера уменьшается.
G>Если у тебя запрос генерируется на основе входных параметров, то что?
... то компилятор "видит" как такой запрос генерируется.
Или ты говоришь о простом параметре-константе в каком-нить предикате (навроде select * from users where id = concrete_id)?
Этот сценарий даже обсуждать облом, тут всё ясно.
А вот первый вариант может даже дать некий комбинаторный взрыв, угу.
Предлагаю его оценить по реальным своим проектам.
Я оценивал — фигня полная.
Ну, т.е. лишнего бинарного кода будет сегерён с гулькин нос по нынешним меркам (5-6 мег на все "взрывы", где самих "врывов" даже в большой системе весьма счётное кол-во — единицы/десятки, остальное всё прекрасно обходится без взрывов, чиста через параметры хранимок).
V>>В современном С++ можно что-то типа такого:
...
G>Уверен? Как выражение x.StartDate.Date + x.Duration / 24 превратится в часть запроса?
Превратится на этапе компиляции из некоего своего AST.
Лямбда — это ж полноправная единица языка, что не так?
G>Какие типы будут у t, x и его свойств, возвращаемого значения?
Я переводил твой пример. А у тебя t задаётся "где-то еще".
Остальные типы просто выводятся современным С++.
V>>Гуглить "named tuple", это довольно популярное игрище.
V>>https://github.com/duckie/named_types/tree/master/test
V>>http://vitiy.info/named-tuple-for-cplusplus/
V>>В "более функциональном" языке можно было с более простым синтаксисом лямбды сделать...
G>Это как бы в теории
Почему в теории? В том же Хаскеле синтаксис лямбды весьма лаконичен.
Но даже и этот синтаксис можно упростить до (ты правильно говорил) простого цитирования.
Просто я возражал насчёт прям-таки обязательности наличия цитирования.
В моём примере выше можно заменить лямбды на ф-ии и всё останется работоспособным, просто будет менее удобным.
Честно говоря — и тот код неудобен, можно было поинересней нарисовать.
Просто не хотелось сходу гнать совсем уж отсебятину, лучше двигаться поэтапно — смотреть что уже есть, чего не хватает, что мешает и почему.
В общем, обсуждаемое тут — это в том числе вопросы удобства "нового SQL" в сравнении чем-то нынешним.
А раз так, то нельзя "запрещать" мне желать любые теоретически-возможные вкусняшки.
(остальное потом)