Clickhouse пока не поддерживает (февраль 2018) EXPLAIN и не имеет механизмов профилирования. Однако, можно использовать записи в логе для базового анализа эффективности запроса.

Представим, что мы работаем с такой таблицей stats:

┌─name────┬─type─────┬─default_type─┬─default_expression─┐
│ date    │ Date     │              │                    │
│ time    │ DateTime │              │                    │
│ url     │ String   │              │                    │
│ post_id │ UInt32   │ DEFAULT      │ CAST(0 AS UInt32)  │
└─────────┴──────────┴──────────────┴────────────────────┘

Выполним простой запрос:

SELECT count(*) FROM stats

# тестовый запрос к таблице

Не забудьте убедиться, что в config.xml указан максимальный уровень логирования:

...
<logger>
        <level>trace</level>
        <log>/var/log/clickhouse-server/clickhouse-server.log</log>
        ...
</logger>
...

# config.xml обычно лежит в /etc/clickhouse-server/config.xml

Теперь посмотрим, что будет в логе:

tail -f /var/log/clickhouse-server/clickhouse-server.log

# учтите, что в лог могут попадать и другие записи, не имеющие отношения к запросу

2018.02.27 12:32:15.874452 [ 5 ] <Debug> executeQuery: (from [::1]:56894, query_id: c2e76e9a-b6f1-4e88-98a0-c1dc8fa948b8) select count(*) from stats
2018.02.27 12:32:15.874932 [ 5 ] <Debug> default.stats (SelectExecutor): Key condition: unknown
2018.02.27 12:32:15.875036 [ 5 ] <Debug> default.stats (SelectExecutor): MinMax index condition: unknown
2018.02.27 12:32:15.875137 [ 5 ] <Debug> default.stats (SelectExecutor): Selected 6 parts by date, 6 parts by key, 82 marks to read from 6 ranges
2018.02.27 12:32:15.875396 [ 5 ] <Trace> default.stats (SelectExecutor): Reading approx. 671744 rows
2018.02.27 12:32:15.875529 [ 5 ] <Trace> InterpreterSelectQuery: FetchColumns -> Complete
2018.02.27 12:32:15.875768 [ 5 ] <Debug> executeQuery: Query pipeline:
Expression
 Expression
  Aggregating
   Concat
    Expression
     MergeTreeThread

2018.02.27 12:32:15.876214 [ 22392 ] <Trace> Aggregator: Aggregating
2018.02.27 12:32:15.876539 [ 22392 ] <Trace> Aggregator: Aggregation method: without_key
2018.02.27 12:32:15.877893 [ 22392 ] <Trace> Aggregator: Aggregated. 641935 to 1 rows (from 1.224 MiB) in 0.001 sec. (492070877.646 rows/sec., 938.551 MiB/sec.)
2018.02.27 12:32:15.878167 [ 22392 ] <Trace> Aggregator: Merging aggregated data
2018.02.27 12:32:15.879097 [ 5 ] <Information> executeQuery: Read 641935 rows, 1.22 MiB in 0.004 sec., 145220297 rows/sec., 276.99 MiB/sec.
2018.02.27 12:32:15.879455 [ 5 ] <Trace> virtual DB::MergingAndConvertingBlockInputStream::~MergingAndConvertingBlockInputStream(): Waiting for threads to finish
2018.02.27 12:32:15.879565 [ 5 ] <Debug> MemoryTracker: Peak memory usage (for query): 3.07 MiB.
2018.02.27 12:32:15.879618 [ 5 ] <Debug> MemoryTracker: Peak memory usage (for user): 3.07 MiB.
2018.02.27 12:32:15.879661 [ 5 ] <Debug> MemoryTracker: Peak memory usage (total): 3.07 MiB.
2018.02.27 12:32:15.879712 [ 5 ] <Information> TCPHandler: Processed in 0.005 sec.

Некоторые из этих данных дают понятие о том, насколько эффективно выполняется запрос:

  • Key condition: unknown означает, что индекс не будет использован.
  • Selected 6 parts by date означает, что данные будут прочитаны из 6 частей таблицы (82 засечек). Данные о всех существующих частях таблицы есть в табличке "system.parts".
  • Reading approx. 671744 rows позволит оценить, какое количество строк будет прочитано.
  • Peak memory usage (for query): 3.07 MiB позволит оценить потребляемый объем RAM.

В целом, этот запрос прочитал все данные из таблицы. Теперь выполним запрос, который будет использовать индекс:

select count(*) from stats where post_id = 758;

# колонка post_id объявлена первичным ключом

В этом случае интересующие нас записи в логе будут выглядеть так:

...
 [ 28 ] <Debug> default.stats (SelectExecutor): Key condition: (column 0 in [758, 758])
 [ 28 ] <Debug> default.stats (SelectExecutor): Selected 9 parts by date, 9 parts by key, 9 marks to read from 9 ranges
 [ 28 ] <Trace> default.stats (SelectExecutor): Reading approx. 73728 rows
...

Как видно, во втором случае Clickhouse использовал индекс. В результате чтения данных из 9 частей таблиц (но только 9 засечек) было обработано всего 73728 строк (в 10 раз меньше предыдущего запроса).

TL;DR

Clickhouse не поддерживает EXPLAIN, но базовое представление о запросе можно получить из лога clickhouse-server.log.