PREWHERE can make filtering more efficient by reducing the amount of data read. By default, ClickHouse applies this optimization, even when a query does not explicitly specify PREWHERE, by moving eligible conditions from WHERE to PREWHERE. You can specify PREWHERE explicitly to control which conditions are applied at this stage.
With PREWHERE, ClickHouse first reads only the columns needed to evaluate the condition. It then reads the other columns required by the query only for blocks that contain at least one matching row. This can reduce the amount of data read when the condition uses fewer columns than the rest of the query and filters out many blocks.
Controlling PREWHERE manually
Specify PREWHERE manually when a condition references a small number of columns and filters out many rows. This can reduce the amount of data read for the remaining columns.
A query can contain both PREWHERE and WHERE. In this case, PREWHERE is evaluated first.
Set optimize_move_to_prewhere to 0 to prevent ClickHouse from automatically moving conditions from WHERE to PREWHERE.
For queries with the FINAL modifier, ClickHouse moves conditions from WHERE to PREWHERE only when both optimize_move_to_prewhere and optimize_move_to_prewhere_if_final are enabled.
By default,
PREWHERE is evaluated before FINAL, so FROM ... FINAL queries may produce unexpected results when PREWHERE references columns outside the table’s ORDER BY key.PREWHERE with JOIN
A PREWHERE condition in a query with a JOIN can directly reference columns from at most one table. ClickHouse applies the condition to that table’s rows before they reach the join.
By contrast, a WHERE condition logically filters the joined result, although the optimizer may apply it before the join when doing so does not change the result. Using the same condition in PREWHERE and WHERE can therefore produce different results, particularly with outer joins.
The following example creates two tables to demonstrate this difference:
PREWHERE filters table_2 before the LEFT JOIN, so the row from table_1 with id = 1 remains unmatched:
WHERE filters the joined result, removing the row with id = 1:
Limitations
PREWHERE is only supported by tables from the *MergeTree family.