На этой неделе мне довелось делать обширный рефакторинг в проекте, написанном на Go. После нескольких часов написания кода я запустил тесты и получил ошибку: import cycle not allowed.
Такую ошибку мы получаем в Go, если пакет A использует код из пакета B, а, в свою очередь, пакет B импортирует пакет A. Говоря просто, A и B как-то очень тесно зависят друг от друга. И так как в Go такая ситуация недопустима, то первая идея - объединить пакеты A и B в один, т.е. перенести код из B в A или наоборот. Другое решение - выделить общий код в пакет C, который будут импортировать как A, так и B. В моем случае я объединил оба пакета и, признаюсь, код стал сильно проще.
Почему в Go запрещены циклические зависимости? Для того чтобы это понять нужно смоделировать ошибку циклической инициализации:
// Available at: https://play.golang.com/p/nOlfgNEhdCi package main var A int = B var B int = A func main() {} // Compile error message: // ./prog.go:3:5: initialization cycle for A // ./prog.go:3:5: A refers to // ./prog.go:4:5: B refers to // ./prog.go:3:5: A
Как в случае кода выше присвоить начальное значение переменной A или B? Это невозможно. Отследить такие циклические инициализации в рамках одного пакета несложно, но дольше и ресурснее в пределах нескольких пакетов. Для такого отслеживания понадобился бы анализ исходного кода всех этих пакетов, что осложняет инкрементную компиляцию.
Инкрементная компиляция позволяет собирать только те пакеты Go-проекта, которые перетерпели изменения. Вносим правки в пакет A, только он и компилируется. Это почти всегда так. За счет этого получаем быструю компиляцию. Теперь представим, что нужно проанализировать код всех пакетов и убедиться, что нет циклических инициализаций. Отказ же от циклических зависимостей делает такой анализ ненужным и, соответственно, скорость компиляции проекта высокой.
Пакет в Go - это единица компиляции (compilation unit).
А как в других языках программирования? В Rust, например, циклические зависимости модулей разрешены (модули - аналог пакетов в Go), но они же запрещены на более высоком уровне, на уровне крейтов (крейт - аналог модуля в Go).
Начиная с 12 версии PostgreSQL, из коробки, можно включить модуль auto_explain
. Этот модуль
логгирует (в stderr, stdout, файл и т.д. - зависит от настроек логов в вашем инстанесе PostgreSQL)
план выполнения запросов, выполняющихся более auto_explain.log_min_duration
мс. Логгировать можно
в JSON, YAML, текстовом форматах. В лог попадет расшифровка плана выполнения запроса как если бы вы сделали
EXPLAIN для медленного запроса. Конфигурация модуля позволяет настраивать параметры EXPLAIN: ANALYZE, включение
таймингов, буферов и т.д.
Для каких задач предпочесть ClickHouse? Для начала немного про OLAP (Online Analytical Processing). Такие аналитические базы данных оптимизированы под выполнение запросов с агрегатными (те, которые возвращают одно значение для набора значений) функциям, например, AVG, SUM, COUNT и т.д. На сайте бенчмарков видно, что для подобных выборок с агрегатными функциями и группировками PostgreSQL работает в 700 раз медленнее, а MySQL в 2000 раз медленнее. Для чего же нужны такие запросы?