Yandex ClickHouse support by Flexberry ORM.
Перед запуском тестов нужно запустить Docker-контейнер с ClickHouse:
docker-compose up -d
[WIP] Yandex ClickHouse support by Flexberry ORM
Home Page: https://www.nuget.org/packages/NewPlatform.Flexberry.ORM.ClickHouseDataService
License: MIT License
Вычитываются не все данные, которые имеются в БД ClickHouse и удовлетворяют условиям фильтрации
Должны возвращаться все данные, которые удовлетворяют условиям фильтрации
В ReadMe к ClickHouse.ADO написано, что надо использовать NextResult. У нас в методе ReadFirst этот метод вызывается.
Дальнейшая вычитка производится в методе ReadNext, который не переопределён в ClickHouseDataService – используется реализация из SQLDataService.
Соответственно, в этом методе ReadNext происходит вычитка данных в цикле, пока что-то приходит из reader.Read().
Я предполагаю, что может быть после окончания reader.Read() надо попробовать снова выполнить NextResult(). Для этого нужно в ClickHouseDataService переопределить метод ReadNext, скопировать его код из ORM и добавить недостающую логику с NextResult.
git clone
.\packages\NewPlatform.Flexberry.ORM.ClickHouseDataService.1.0.0-alpha02\lib\net45\
8ч.
Реализовать ClickHouseDataService в полном объёме.
В данном репозитории.
Проект на GitHub: <адрес>
Ветка: develop
В качестве примера реализации можно использовать PostgresDataService и MongoDbDataService.
*<Сколько времени в часах может понадобиться на решение поставленной задачи среднему по знаниям и навыкам разработчику. В эту оценку времени в т.ч. входит работа над тестами и документацией. Задачи не должны быть сформулированы на длительности более 16 ч.
<Дополнительный материал который может пригодиться, чтобы успешно справиться с поставленной задачей (номер задачи, запись на форуме и т.д.)>
В секции FROM добавляются скобки, которые не работают с ClickHouse.
В секции FROM в SQL запросе не должно быть обрамляющих скобок
Генератор сгенерил такой вот запрос:
SELECT
"Источник",
"Источник.Editor",
"Время",
"НомерТС",
"Скорость",
"ОграничениеСкорости",
"ИдентификаторМатериала",
"STORMMainObjectKey",
"STORMJoinedMasterKey0",
"STORMJoinedMasterKey1",
"STORMNETDATAOBJECTTYPE"
FROM (
SELECT
"ФотофиксацияТС0"."Источник" as "Источник",
"ФотофиксацияТСИсточник0"."Editor" as "Источник.Editor",
"ФотофиксацияТС0"."Время" as "Время",
"ФотофиксацияТС0"."НомерТС" as "НомерТС",
"ФотофиксацияТС0"."Скорость" as "Скорость",
"ФотофиксацияТС0"."ОграничениеСкорости" as "ОграничениеСкорости",
"ФотофиксацияТС0"."ИдентификаторМатериала" as "ИдентификаторМатериала",
"ФотофиксацияТС0"."primaryKey" as "STORMMainObjectKey",
"ФотофиксацияТСИсточник0"."primaryKey" as "STORMJoinedMasterKey0",
"ФотофиксацияТС0"."Источник" as "STORMJoinedMasterKey1", 0 as "STORMNETDATAOBJECTTYPE"
FROM
("ФотофиксацияТС" "ФотофиксацияТС0"
LEFT JOIN "Источник" "ФотофиксацияТСИсточник0"
ON "ФотофиксацияТС0"."Источник" = "ФотофиксацияТСИсточник0"."primaryKey")
) "STORMGENERATEDQUERY"
WHERE ( "STORMMainObjectKey" = 'a46002e9-4913-44ca-9857-2587af9ccfbf')
И тестовое приложение упало.
Попробовал при помощи clickhouse-client его выполнить, выдает:
Syntax error: failed at position 1200:
SELECT "Источник", "Источник.Editor", "Время", "НомерТС", "Скорость", "ОграничениеСкорости", "ИдентификаторМатериала", "STORMMainObjectKey", "STORMJoinedMasterKey0", "STORMJoinedMasterKey1", "STORMNETDATAOBJECTTYPE" FROM ( SELECT "ФотофиксацияТС0"."Источник" as "Источник", "ФотофиксацияТСИсточник0"."Editor" as "Источник.Editor", "ФотофиксацияТС0"."Время" as "Время", "ФотофиксацияТС0"."НомерТС" as "НомерТС", "ФотофиксацияТС0"."Скорость" as "Скорость", "ФотофиксацияТС0"."ОграничениеСкорости" as "ОграничениеСкорости", "ФотофиксацияТС0"."ИдентификаторМатериала" as "ИдентификаторМатериала", "ФотофиксацияТС0"."primaryKey" as "STORMMainObjectKey", "ФотофиксацияТСИсточник0"."primaryKey" as "STORMJoinedMasterKey0", "ФотофиксацияТС0"."Источник" as "STORMJoinedMasterKey1", 0 as "STORMNETDATAOBJECTTYPE" FROM ("ФотофиксацияТС" "ФотофиксацияТС0" LEFT JOIN "Источник" "ФотофиксацияТСИсточник0" ON "ФотофиксацияТС0"."Источник" = "ФотофиксацияТСИсточник0"."primaryKey") ) "STORMGENERATEDQUERY" WHERE ( "STORMMainObjectKey" = 'a46002e9-4913-44ca-9857-2587af9ccfbf');
Expected one of: SELECT query, possibly with UNION, SELECT query, subquery, possibly with UNION, SELECT, WITH, SELECT subquery, list of elements, SELECT query
Исправил запрос на:
SELECT "Источник", "Источник.Editor", "Время", "НомерТС", "Скорость", "ОграничениеСкорости", "ИдентификаторМатериала", "STORMMainObjectKey", "STORMJoinedMasterKey0", "STORMJoinedMasterKey1", "STORMNETDATAOBJECTTYPE" FROM ( SELECT "ФотофиксацияТС0"."Источник" as "Источник", "ФотофиксацияТСИсточник0"."Editor" as "Источник.Editor", "ФотофиксацияТС0"."Время" as "Время", "ФотофиксацияТС0"."НомерТС" as "НомерТС", "ФотофиксацияТС0"."Скорость" as "Скорость", "ФотофиксацияТС0"."ОграничениеСкорости" as "ОграничениеСкорости", "ФотофиксацияТС0"."ИдентификаторМатериала" as "ИдентификаторМатериала", "ФотофиксацияТС0"."primaryKey" as "STORMMainObjectKey", "ФотофиксацияТСИсточник0"."primaryKey" as "STORMJoinedMasterKey0", "ФотофиксацияТС0"."Источник" as "STORMJoinedMasterKey1", 0 as "STORMNETDATAOBJECTTYPE" FROM "ФотофиксацияТС" "ФотофиксацияТС0" LEFT JOIN "Источник" "ФотофиксацияТСИсточник0" ON "ФотофиксацияТС0"."Источник" = "ФотофиксацияТСИсточник0"."primaryKey") "STORMGENERATEDQUERY" WHERE ( "STORMMainObjectKey" = 'a46002e9-4913-44ca-9857-2587af9ccfbf');
/* убрал скобки в FROM ( "ФотофиксацияТС" "ФотофиксацияТС0" LEFT JOIN … "ФотофиксацияТСИсточник0"."primaryKey") "STORMGENERATEDQUERY" */
Запрос исполнился и выдал результат
Скобки добавляются вот тут: https://github.com/Flexberry/NewPlatform.Flexberry.ORM/blob/62461760cb51684878f57f587a7f309173faf049/ICSSoft.STORMNET.Business/SQLDataService/SQLDataService.cs#L1549
Соответственно, тебе надо попробовать переопределить в ClickHouseDataService метод
string GenerateSQLSelect(LoadingCustomizationStruct customizationStruct, bool ForReadValues, out STORMDO.Business.StorageStructForView[] StorageStruct, bool Optimized)
взяв его целиком из SQLDataService
и исправив только эту строку.
Важное замечание: берём исходный код ORM версии v5.0.0
. Переключиться на него можно через соответствующий тег.
git clone
.\packages\NewPlatform.Flexberry.ORM.ClickHouseDataService.1.0.0-alpha02\lib\net45\
2ч
Изменить алгоритм формирования с UUID4 на UUID1
Если формирование primaryKey записи производится в рамках драйвера необходимо
изменить алгоритм формирования с UUID4 на UUID1.
Генерация UUID по типу UUD4 (случайный) приводит к неэффективной работе ClickHouse со столбцами такого типа.
Необходимо изменить генерацию UUID со случайного (UUID4) на увеличивающийся UUID по типу UUID1
Как правило первичные ключи формируются на основе стандарта UUID вариант 4.
Он обеспечиват формирование случайного уникального идентификатора.
В Clickhouse случайные последовательности в столбце primaryKey
очень плохо сжимаются.
Кроме того в материализованном представлении отсортированном по primaryKey при вставке
случайных последовательностей в ключе сортировки приводит к большим накладным расходам из за формирования большого количества (несколько тысяч) "частей данных".
Для решения этой проблемы необходимо при формировании primaryKey
использовать
инкрементальный UUID
в котором каждый последующий UUID
содержит бОльшую часть символов предыдущего.
Для этой цели более всего подходит UUID версии 1,
так как формируется на основе текущего времени.
Правда в стандартной реализации он не носит инкрементального характера, так как
сначала последовательности в UUID записывается time_low
, а затем time_mid
.
Для обеспечения инкрементальности необходмо в начало UUID (первые 8 и 4 байта)
разместить постоянный идентификатор node
(последние 12 байт).
А на место этого идентификатора последовательно поместить
time_mid
time_low
2-я и третья четверка байт остается на месте, так как они хранят флаги M
и N
идентифицирующие версию UUID1.
На языке Python данная операция выглядит так:
ss=str(uuid.uuid1()).split('-')
primarykey = uuid.UUID('-'.join([ss[4][0:8],ss[4][8:],ss[2],ss[3],ss[1]+ss[0]])
Использование такого UUID существенно сокращает накладные расходы в ClickHouse
.
Проект на GitHub: https://github.com/Flexberry/NewPlatform.Flexberry.ORM.ClickHouseDataService
Ветка: master
16 часов
Обеспечить при запрсое данных (SELECT) выбор таблицы с нужными параметрами сортировки
В ClickHouse для ускорения выборки данных (SELECT) по разным ключам на основе одной "большой" таблицы, отсортированной по одним ключам создаюются материализованные предсталения, отсортированные по другим ключам. Данные материализованные представления играют роль индексов в обычных реляционных базах.
При выборке данных необходимо проанализировать имена столбцов в условии WHERE и для выборки данных использовать представление, отсортированное по столбцам содержащихся в условии WHERE.
Это обеспечивает существенное сокращения времени получения записей, так как существенно сокращается объем сканируемых записей.
40 часов
Добавление в запрос SELECT модификатора FINAL для таблиц типа VersionedCollapsingMergeTree
Для корректируемых таблиц типа VersionedCollapsingMergeTree, CollapsingMergeTree для исключения удаляемых записей необходимо добавлять после имени таблицы в FROM <имя_таблицы> ...
модификатор FINAL
: FROM <имя_таблицы> FINAL ...
Этот способ не рекомендуют использовать для "больших" таблиц и предлагают использовать группировку по ключам сортировки GROUP BY
с модификацией списка выбираемых столбцов, но этот способ сложен в реализации.
Будем надеяться, что в последующих релизах ClickHouse эту проблему решат.
По крайней мере в TODO на 2020 год эта тема обозначена.
Добавить GitHub Action для сборки проекта.
Взять за основу https://github.com/Flexberry/NewPlatform.Flexberry.LogService/blob/develop/.github/workflows/build.yml
Обеспечить поддержку буферизации на уровне сервиса данных
При добавлении информации в таблицы ClickHouse необходимо буферизировать данные,
так как в противном случае вставки будут неэффективными.
Обычно для этих целей используются proxy-сервера. Но все они к сожалению поддерживают только HTTP-интерфейс.
У нас же драйвер использует Native TCP интерфейс.
Поэтому задача буферизации данных в настоящее время ложится на приложение.
Необходимо реализовать простой механизм формировния буфера записей по двум параметрам:
Проект на GitHub: https://github.com/Flexberry/NewPlatform.Flexberry.ORM.ClickHouseDataService
Ветка: master
16 часов
Требуется опустить версию ORM до релизной 5.0
Нужно исправить код в соответствии с внутренним API версии 5.0, поскольку 5.1 ещё не вышла.
DataService должен продолжать работать.
2 ч.
Обновить csproj до sdk-формата.
Взять за основу https://github.com/Flexberry/NewPlatform.Flexberry.LogService
Обновить ORM до версии 6.0-beta. Сделать в отдельной ветке и следующей мажорной версией.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.