BI Consult Desktop Logo BI Consult Mobile Logo
  • Russian BI Исследование российских bi
  • Перейти на Fine BI
  • Контакты
  • +7 812 334-08-01
    +7 499 608-13-06
  • Отправить сообщение
  • Главная
  • Продукты Эксперт-BI
    • Дистрибуция
    • Розничная торговля
    • Производство
    • Операторы связи
    • Страхование
    • Банки
    • Лизинг
    • Логистика
    • Нефтегазовый сектор
    • Медицина
    • Сеть ресторанов
    • E-Commerce
    • Сельское хозяйство
    • Энергетика
    • FMCG
    • Девелоперы
    • Маркетплейсы
    • Пищевая промышленность
    • Фармацевтика
    • Построение Data Platform
    • Цифровая трансформация
    • Управление по KPI
    • Финансы
    • Продажи
    • Склад
    • HR
    • Маркетинг
    • Внутренний аудит
    • Категорийный менеджмент
    • S&OP и FP&A
    • Геоаналитика
    • Цепочки поставок (SCM)
    • AutoML
    • Process Mining
    • IBP
    • ИТ (CIO)
    • Закупки
  • Платформы
    • Системы бизнес-анализа (BI)
    • Интегрированное бизнес-планирование (IBP)
    • Хранилища данных (DWH / Lakehouse)
    • Каталоги данных (Data Catalog)
    • Системы ETL и ELT
    • AI / Исскуственный интеллект
    • Шина данных (ESB)
    • Система управления мастер-данными (MDM)
    • Семантический слой
  • Услуги
    • Переход на отечественные BI и DWH системы
    • Консалтинг
    • Пилотный проект
    • Обучение и сертификация
    • Бесплатное обучение
    • Поддержка
    • Технические задания
    • Сбор требований для проекта внедрения BI-системы
    • CI/CD для DWH
    • Аудит BI приложений и DWH
    • Выделенная команда
    • Настойка и поддержка баз данных
    • Разработка BI Стратегии
    • Styleguide для BI-системы
    • Как выбрать BI-систему
  • Курсы
    • Учебный курс Информационная грамотность (Data Literacy)
    • Учебный курс для бизнес-аналитиков
    • Учебный курс для системных аналитиков
    • Учебный курс по Data Governance
    • Учебный курс Как стать CDO
    • Учебный курс Современная архитектура хранилища данных
    • Учебный курс по Fine BI
    • Учебный курс по FineReport
    • Учебный курс по DWH
    • Учебный курс по Data Science (ML, AI)
    • Учебный курс по PostgreSQL
    • Учебный курс по Greenplum
    • Учебный курс по Apache Airflow и NiFi
    • Учебный курс по Open-source BI
    • Учебный курс по ClickHouse
    • Учебный курс по DataLens
    • Учебный курс по Loginom
    • Учебный курс по Modus BI и ETL
    • Учебный курс по Visiology
    • Учебный курс по dbt (Data Build Tool)
  • Компания
    • Руководство
    • Новости
    • Клиенты
    • Карьера
    • Скачать
    • Контакты

BI

  • FineBI
  • FineReport
  • FineDataLink
  • FineChatBI (FineAI)
  • Коннекторы данных из 1С в BI
  • Airflow / Nifi
  • Visiology
  • PIX BI
  • Modus BI
  • Yandex.DataLens
  • Open-source BI: Superset/Metabase
  • Luxms BI
  • AW BI + Alpha BI
  • FlyBI + Форсайт. Аналитическая Платформа
  • Loginom
  • Триафлай
  • AI / Исскуственный интеллект
  • Optimacros
  • Навигатор BI
  • Семантический слой

СУБД

  • Arenadata
  • ClickHouse
  • Greenplum
  • Postgres Professional
  • TData

Другое

  • Построение Data Platform
    • Аналитическое хранилище данных
    • Data Lake и Data Engineering
    • Подробнее про Data Lake
    • Внедрение Lakehouse
      • Apache Doris
      • StarRocks
      • Trino
    • Миграция витрин из пропиетарных DWH на новый стек
    • Учебный курс "Современная архитектура хранилища данных"
Главная » Курсы по системам бизнес-анализа и методологии » Учебный курс по ClickHouse » Новые кодировки для того, чтобы увеличить производительность ClickHouse

Новые кодировки для того, чтобы увеличить производительность ClickHouse

Современные аналитические базы данных не смогли бы существовать без эффективной компрессии данных. Хранение данных становится дешевле, но размеры данных растут гораздо быстрее. Закон Мура о Больших Данных опережает аналогию в аппаратном обеспечении. В этой статье мы опишем и протестируем новейшие кодировки ClickHouse, которые особенно актуальны для временных рядов. И мы  гордимся тем, что Altinity добавили некоторые из них в ClickHouse.

Данная статья представляет собой  анонс новых кодировок для ClickHouse 19.11. на момент написания статьи данная версия еще недоступна. Для тестирования новых кодировок ClickHouse может быть настроен из источника либо можно попробовать тестовую сборку.

 

Кодировки и обзор компрессии

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

В течение многих лет ClickHouse поддерживал два алгоритма компрессии данных: LZ4 (по умолчанию) и ZSTD. Эти алгоритмы иногда имеют логику для применения кодировки внутри, но они не знают о типах данных ClickHouse. Знание типа данных и характера данных позволяет нам более эффективно кодировать данные. В течение последних нескольких месяцев синтаксис ClickHouse был расширен, что позволило включить кодировки уровня столбцов, новые кодировки были добавлены в ClickHouse:

  • Delta. Delta-кодирование сохраняет разницу между последовательными значениями. Разница, как правило, имеет меньший размер байта и кардинальность, особенно для последовательностей. Она может быть эффективно сжата при помощи LZ4 или ZSTD;
  • DoubleDelta. С помощью данной  кодировки ClickHouse сохраняет разницу между последовательными дельтами. Он обеспечивает еще лучшие результаты для медленно изменяющихся последовательностей. Чтобы использовать аналогию из физики, Delta кодирует скорость, а DoubleDelta – ускорение;
  • Gorilla. Данная кодировка родилась под вдохновением от недавней статьи, опубликованной на Facebook [http://www.vldb.org/pvldb/vol8/p1816-teller.pdf], и никто больше не помнит академического названия данного алгоритма. Оно очень эффективно для значений, которые меняются не часто. Он применим как к плавающим, так и к целочисленным типам данных;
  • T64. Эта кодировка уникальна для ClickHouse, она вычисляет максимальные и минимальные значения для кодированного диапазона, а затем удаляет более высокие биты, транспонируя 64-битную матрицу (откуда и происходит имя T64). В итоге мы получаем более компактное битовое представление тех же данных. Кодировка является универсальной для целых типов данных и не требует каких-либо особых свойств от данных, кроме локальности значений.

 

Кодировки могут быть заданы как часть определения столбца, используя ключевое слово 'Codec'. Пример ниже определяет кодировку DoubleDelta для столбца. Обратите внимание, что он отключает сжатие по умолчанию.

ts DateTime Codec(DoubleDelta) – закодировано, но компрессия при этом отсутствует

 

Для того, чтобы обеспечить и кодирование и сжатие, кодеки могут быть цепными, как показано ниже:

ts DateTime Codec(DoubleDelta, LZ4) – закодировано, компрессия применена

 

Кодировки Delta, DoubleDelta и Gorilla можно найти во многих базах данных временных рядов. Delta и DoubleDelta традиционно используются для отметок времени, а кодировка Gorilla - для значений. Хорошим примером являются InfluxDB и Prometheus. ClickHouse хорошо конкурирует с InfluxDB с точки зрения производительности, но проигрывает ему, когда речь идет об эффективности сжатия. Использование новых кодировок исправит этот зазор. Давайте протестируем их!

 

Методология тестирования

Будем исследовать кодировки, используя следующие критерии:

  • Эффективность кодирования без сжатия для различных типов данных;
  • Эффективность кодирования с применением сжатия LZ4 и ZSTD;
  • Эффективность сжатия LZ4 и ZSTD применительно к закодированным данным.

 

Мы использовали 4 разных наборов данных, содержащих 1,000,000 рядов:

  • Монотонная последовательность чисел с постоянными приращениями

(codec_test1_seq). Образец данных: 0,1000,2000,3000,4000,5000,6000,7000,8000,9000, …

  • Монотонная последовательность чисел со случайным приращением (codec_test2_mon). Образец данных: 22,1072,2034,3076,4007,5094,6061,7074,8061,9058, …
  • Постоянная последовательность со случайными скачками (codec_test3_var). Образец данных: 1825,1000,1000,1000,1000,1000,1000,1703,1000,1000, …
  • Случайный набор значений ниже 1B (codec_test4_rand). Образец данных: 608745218, 167444263, 620949842, 956686395, 66062863, …

 

Первые три набора данных типичны для приложений временных рядов. Рандомизированное множество является наихудшим сценарием. Каждая таблица наборов данных имеет несколько столбцов, которые представляют различные комбинации типа данных, кодирования и сжатия. Мы также храним незашифрованный столбец в качестве ссылки. Это позволяет нам сравнивать различные комбинации внутри наборов данных и между наборами данных. Подводя итог, мы протестируем следующие комбинации:

  • Типы данных Int32, Int64 *;
  • Кодировки None, Delta, DoubleDelta, Gorilla, T64;
  • Компрессия None, LZ4, ZSTD **
  • Изначально мы планировали протестировать Float32 и Float64 с кодировкой Gorilla, но удалили его, чтобы сделать статью более компактной. Вы можете найти типы плавающих данных и комбинации в скриптах в Приложении.

** Можно настроить уровень сжатия, но мы использовали уровни по умолчанию.

 

Эффективность сжатия и кодирования можно увидеть из таблицы ClickHouse system.columns, которая показывает сжатый и несжатый размер для каждого столбца, а также кодировки и сжатия, которые были применены к столбцу.

Если кому-то интересны подробные примеры SQL, обратитесь к Приложению в конце данной статьи.

 

Результаты эффективности кодирования и сжатия: целые типы

Если посмотреть на результаты ниже, учитывайте размер исходных данных: незашифрованный и несжатый. Это 4000,000 байт для Int32 и 8000000 для Int64. Мы также включаем необусловленный размер данных в качестве ссылки.

Сначала давайте посмотрим на несжатые данные.

Как Вы можете видеть, Delta вообще не сжимает данные, так как по умолчанию размер дельты совпадает с типом данных. Чуть позже мы увидим, что она будет лучше работать с LZ4. DoubleDelta лучше всего подходит для однородных последовательностей и монотонных, но не для случайных данных.

Также очень интересно посмотреть, как работают Gorilla и T64. Случайные данные – это самый лучший пример. Так как мы создали случайные значения ниже 1B, данные подходят для 30 бит. T64 способен обнаружить его и снять дополнительные биты идеально. Вы можете ясно видеть это и для Int32, и для Int64 - размер данных примерно одинаков и близок к 375000000 байт (1,000*30/8).

Gorilla немного хуже на случайных наборах данных (32 бита), но это фантастика для 'var' набора данных. Эталонный тип данных является основным примером использования для такой кодировки, хотя мы были удивлены производительностью Gorilla для целочисленных типов данных в целом.

Далее обратим внимание на компрессию LZ4.

С сжатием LZ4 Delta-кодирование хорошо для всего, кроме случайного набора данных. DoubleDelta, очевидно, является лучшим для случаев временных рядов.

Теперь обратим внимание на ZSTD.

Интересно, что ZSTD может сжимать Delta для последовательностей более эффективно, чем DoubleDelta. Коэффициент сжатия для последовательностей впечатляет 1:800+ как с дельта-кодировкой, так и с ZSTD. T64 является лучшим для случайных данных снова.

Давайте посмотрим на это под другим углом. Для отчета ниже мы объединили все наборы данных временных рядов, чтобы сравнить эффект сжатия и кодирования вместе.

Подводя итог, можно сказать, что Delta и DoubleDelta хорошо работают с конкретными временными рядами данных. DoubleDelta очень эффективен с LZ4, поэтому добавление ZSTD не улучшает его. T64 и Gorilla - отличные кодеки общего назначения, которые можно рекомендовать для всех случаев, когда шаблон данных не известен. Gorilla лучше для временных рядов, но T64 более 'сжатие-дружественный'. Даже если Gorilla может быть более эффективным первоначально, сжатие более эффективно с T64. Но разница не так много. Обратите внимание, что горилла может кодировать поплавки с той же эффективностью, так что для плавающих значений это не так уж сложно.

 

Заключение

Кодеки ClickHouse помогают намного улучшить общее сжатие, уменьшить хранение и увеличить производительность за счет меньшего I/O. Важно понять характер данных и выбрать правильный кодек. Delta-кодировка лучше всего хранит временные столбцы, DoubleDelta должна очень хорошо сжиматься для увеличения счетчиков, а Gorilla лучше всего подходит для датчиков. T64 может использоваться для целочисленных данных при условии, что Вы не храните случайные хеши. Использование кодов также позволяет придерживаться с быстрым LZ4 и уменьшить нагрузку на процессор при декомпрессии данных.

Однако многое еще предстоит сделать. В частности, похоже, что DoubleDelta может быть улучшена для Int32, новая версия кодека T64 была добавлена на прошлой неделе, и есть статья от VictoriaMetrics, которая претендует на значительное улучшение с помощью модифицированного алгоритма Gorilla [https:///medi.com/faun/victoriametrics-achieving-better- bettion-for-time-data--than-gorilla-317bc1f95932]. Мы ожидаем, что еще более эффективные кодеки будут доступны в ClickHouse в течение следующих нескольких месяцев.

Можно пожаловаться, что в этой статье не хватает тестов производительности. Испытания производительности синтетических данных могут ввести в заблуждение. Мы протестируем реальный эффект с помощью тестов TSBS. Оставайтесь с нами.

 

Приложение: подготовка тестовых данных

Ниже приведены скрипты для повторения наших критериев:

DROP TABLE IF EXISTS codec_test1_seq;
CREATE TABLE codec_test1_seq (
 n Int32,
 
 /* No compression */
 n32               Int32 default n Codec(NONE),
 n32_delta         Int32 default n Codec(Delta),
 n32_doubledelta   Int32 default n Codec(DoubleDelta),
 n32_t64           Int32 default n Codec(T64),
 n32_gorilla       Int32 default n Codec(Gorilla),
 n64               Int64 default n Codec(NONE),
 n64_delta         Int64 default n Codec(Delta),
 n64_doubledelta   Int64 default n Codec(DoubleDelta),
 n64_t64           Int64 default n Codec(T64),
 n64_gorilla       Int64 default n Codec(Gorilla),
 f32               Float32 default n Codec(NONE),
 f64               Float64 default n Codec(NONE),
 f32_gorilla       Float32 default n Codec(Gorilla),
 f64_gorilla       Float64 default n Codec(Gorilla),
 
 /* LZ4 compression */
 l_n32             Int32 default n Codec(LZ4),
 l_n32_delta       Int32 default n Codec(Delta, LZ4),
 l_n32_doubledelta Int32 default n Codec(DoubleDelta, LZ4),
 l_n32_t64         Int32 default n Codec(T64, LZ4),
 l_n32_gorilla     Int32 default n Codec(Gorilla, LZ4),
 l_n64             Int64 default n Codec(LZ4),
 l_n64_delta       Int64 default n Codec(Delta, LZ4),
 l_n64_doubledelta Int64 default n Codec(DoubleDelta, LZ4),
 l_n64_t64         Int64 default n Codec(T64, LZ4),
 l_n64_gorilla     Int64 default n Codec(Gorilla, LZ4),
 l_f32             Float32 default n Codec(LZ4),
 l_f64             Float64 default n Codec(LZ4),
 l_f32_gorilla     Float32 default n Codec(Gorilla, LZ4),
 l_f64_gorilla     Float64 default n Codec(Gorilla, LZ4),
 
 /* ZSTD compression */
 z_n32             Int32 default n Codec(ZSTD),
 z_n32_delta       Int32 default n Codec(Delta, ZSTD),
 z_n32_doubledelta Int32 default n Codec(DoubleDelta, ZSTD),
 z_n32_t64         Int32 default n Codec(T64, ZSTD),
 z_n32_gorilla     Int32 default n Codec(Gorilla, ZSTD),
 z_n64             Int64 default n Codec(ZSTD),
 z_n64_delta       Int64 default n Codec(Delta, ZSTD),
 z_n64_doubledelta Int64 default n Codec(DoubleDelta, ZSTD),
 z_n64_t64         Int64 default n Codec(T64, ZSTD),
 z_n64_gorilla     Int64 default n Codec(Gorilla, ZSTD),
 z_f32             Float32 default n Codec(ZSTD),
 z_f64             Float64 default n Codec(ZSTD),
 z_f32_gorilla     Float32 default n Codec(Gorilla, ZSTD),
 z_f64_gorilla     Float64 default n Codec(Gorilla, ZSTD)
) Engine = MergeTree 
PARTITION BY tuple() ORDER BY tuple();
 
DROP TABLE IF EXISTS codec_test2_mon;
CREATE TABLE codec_test2_mon AS codec_test1_seq;
 
DROP TABLE IF EXISTS codec_test3_var;
CREATE TABLE codec_test3_var AS codec_test1_seq;
 
DROP TABLE IF EXISTS codec_test4_rand;
CREATE TABLE codec_test4_rand AS codec_test1_seq;
 
insert into codec_test1_seq (n)
select number*1000 from numbers(1000000) settings max_block_size=1000000;
 
insert into codec_test2_mon (n)
select number*1000+(rand()%100) from numbers(1000000) settings max_block_size=1000000;
 
insert into codec_test3_var (n)
select 1000 + (rand(1)%1000) * (rand(2)%10 = 0) from numbers(1000000) settings max_block_size=1000000;
 
insert into codec_test4_rand (n)
select rand()%(1000000*1000) from numbers(1000000) settings max_block_size=1000000;
 
/* sample rows */
select table, groupArray(n) samples from (
select 'codec_test1_seq' table, n from codec_test1_seq limit 10
union all
select 'codec_test2_mon' table, n from codec_test2_mon limit 10
union all
select 'codec_test3_var' table, n from codec_test3_var limit 10
union all
select 'codec_test4_rand' table, n from codec_test4_rand limit 10
)
group by table order by table;
 
/* validation. It is complicated because of mix of Int and Float types */
select arrayDistinct(avgForEach(CAST(replaceOne(replaceOne(toString(tuple(*)), '(', '['), ')', ']'), 'Array(Int64)'))) avg from codec_test1_seq
union all
select arrayDistinct(avgForEach(CAST(replaceOne(replaceOne(toString(tuple(*)), '(', '['), ')', ']'), 'Array(Int64)'))) avg from codec_test2_mon
union all
select arrayDistinct(avgForEach(CAST(replaceOne(replaceOne(toString(tuple(*)), '(', '['), ')', ']'), 'Array(Int64)'))) avg from codec_test3_var
union all
select arrayDistinct(avgForEach(CAST(replaceOne(replaceOne(toString(tuple(*)), '(', '['), ')', ']'), 'Array(Int64)'))) avg from codec_test4_rand;
 
/* Encoding benchmarks results */
select multiIf(table like '%rand', 'Random', 'Time-Series') dataset_type,
       table, type as data_type, 
       multiIf(compression_codec like '%ZSTD%', 'ZSTD', compression_codec like '%LZ4%', 'LZ4', ' None') compression,
       multiIf(compression_codec like '%DoubleDelta%', 'DoubleDelta', 
               compression_codec like '%Delta%', 'Delta', 
               compression_codec like '%T64%', 'T64',
               compression_codec like '%Gorilla%', 'Gorilla', 
               ' None') encoding,
compression_codec codec, 
sum(data_uncompressed_bytes) uncompressed, 
sum(data_compressed_bytes) compressed, 
round(uncompressed/compressed,1) ratio 
from system.columns 
where table like 'codec_test%' and name != 'n' 
group by dataset_type, table, data_type, compression, encoding, codec
order by dataset_type, table, data_type, compression, encoding, codec
FORMAT CSVWithNames;

 

Узнать стоимость решенияЗапросить видео презентацию

← Предыдущая статья
Как запустить ClickHouse своими силами и выиграть джекпот
Следующая статья →
Как протестировать различные кодеки компрессии

Решения

Анализировать ФинансыУвеличивайте ПродажиОптимальный Склад и ЛогистикаМаркетинговые Метрики

Клиенты
  • Ситилинк

    Электронный дискаунтер «Ситилинк» — один из крупнейших онлайн‑ритейлеров России (3‑е место по объему онлайн‑продаж в рейтинге Data Insight и Ruward 2016 года E‑commerce Index TOP‑100, 8 место в рейтинге Forbes «20 самых дорогих компаний Рунета — 2017»). На рынке работает 9 лет.

    В ассортименте дискаунтера более 50 000 наименований компьютерной цифровой, бытовой и садовой техники, офисной мебели и других товарных категорий. Более 700 мировых брендов в портфеле. Около 4 000 сотрудников по всей России

  • Компания «Бизон-Трейд» является официальным дилером ведущих мировых производителей сельскохозяйственной техники (Fendt, Valtra, Lemken и др.) на Юге России. Входит в состав агрохолдинга «Бизон», основанного в 1994 году. Имеет 8 филиалов в Краснодарском и Ставропольском краях, Ростовской области.

  • «Балтийский лизинг» — первая компания в России, получившая лицензию № 0001 от Министерства экономики РФ на лизинговую деятельность, лицензия зарегистрирована 2 сентября 1996 года. «Балтийский лизинг» работает на российском рынке 33 года: компания представлена 79 филиалами по всей стране, сегодня в штате более 1300 сотрудников. За последние десять лет компания профинансировала имущество для 80 000 клиентов.

  • КАМИ – компания-лидер по поставкам тяжёлых станков в России, занимающаяся продажей и обслуживанием оборудования для обработки металла и дерева, изготовления мебели и не только. На сегодняшний день в компании работают более 1300 человек, запущено 10 обучающих центров, в продаже более 7000 единиц техники. 

  • Решения
    • Дистрибуция
    • Розничная торговля
    • Производство
    • Операторы связи
    • Страхование
    • Банки
    • Лизинг
    • Логистика
    • Нефтегазовый сектор
    • Медицина
    • Сеть ресторанов
    • E-Commerce
    • Энергетика
    • Фармацевтика
  • Услуги
    • Переход на отечественные BI и DWH
    • Консалтинг
    • Пилотный проект
    • Обучение и сертификация
    • Бесплатное обучение
    • Техническая поддержка
    • Технические задания
    • Сбор требований для проекта внедрения BI-системы
    • CI/CD для DWH
    • Аудит BI приложений
    • Выделенная команда
    • Настойка и поддержка баз данных
    • Разработка BI Стратегии
    • Styleguide для BI-системы
    • Как выбрать BI-систему
  • Платформы
    • FineBI
    • FineReport
    • FineDataLink
    • Коннекторы данных из 1С в BI
    • Airflow + NiFi
    • Visiology
    • Luxms BI
    • Modus BI
    • PIX BI
    • Arenadata
    • ClickHouse
    • Greenplum
    • Postgres Professional
    • Open-source BI: Superset/Metabase
    • Loginom
    • Yandex.DataLens
    • AI / Исскуственный интеллект
    • Optimacros
    • Шины данных
  • Курсы
    • Учебный курс Информационная грамотность
    • Учебный курс для бизнес-аналитиков
    • Учебный курс для системных аналитиков
    • Учебный курс по Data Governance
    • Учебный курс Как стать CDO
    • Учебный курс Современная архитектура хранилища данных
    • Учебный курс по Fine BI
    • Учебный курс по FineReport
    • Учебный курс по DWH
    • Учебный курс по Data Science (ML, AI)
    • Учебный курс по PostgreSQL
    • Учебный курс по Apache Airflow и NiFi
    • Учебный курс по Open-source BI
    • Учебный курс по ClickHouse
    • Учебный курс по DataLens
    • Учебный курс по Loginom
    • Учебный курс по Modus BI и ETL
    • Учебный курс по Visiology
    • Учебный курс по dbt
  • Функциональные решения
    • Создание Data Lake
    • Цифровая трансформация
    • Управление по KPI
    • Финансы
    • Продажи
    • Склад
    • HR
    • Маркетинг
    • Внутренний аудит
    • Категорийный менеджмент
    • S&OP и прогнозная аналитика
    • Геоаналитика
    • Цепочки поставок (SCM)
    • AutoML
    • Process Mining
    • Сквозная аналитика
  • Компания
    • О нас
    • Руководство
    • Новости
    • Клиенты
    • Скачать
    • Контакты
    • Политика конфиденциальности
RutubeVkontakteLinkedInYouTube
ООО "Би Ай Консалт",
ИНН: 7811437757,
ОГРН: 1097847154184
199178, Россия,
Санкт-Петербург,
6-ая линия В.О., Д. 63, 4 этаж
Тел: +7 (812) 334-08-01
Тел: +7 (499) 608-13-06
E-mail: info@biconsult.ru

 

 

 

 

 

×

Пользуясь сайтом, вы соглашаетесь с использованием cookies и политикой конфиденциальности.