---
title: "Predicate pushdown"
description: "Predicate pushdown is a query optimization that moves filter conditions as close as possible to the data source, so fewer rows (or bytes) are read before filtering happens."
canonical: "https://motherduck.com/glossary/predicate-pushdown/"
related:
  - title: "Optimizing query performance | MotherDuck Docs"
    url: "https://motherduck.com/docs/key-tasks/query-performance/"
  - title: "DuckLake Lakehouse: Getting Started to Going Fast | MotherDuck"
    url: "https://motherduck.com/videos/ducklake-lakehouse-getting-started/"
  - title: "Give Your Agent Write Access"
    url: "https://motherduck.com/blog/give-your-agents-write-access/"
---

# Predicate pushdown

> Predicate pushdown is a query optimization that moves filter conditions as close as possible to the data source, so fewer rows (or bytes) are read before filtering happens.

## Overview

Without pushdown, a naive query engine would read an entire table or file into memory and only then apply a `WHERE` clause. Predicate pushdown instead moves the filter down into the scan itself — or even into the storage format or remote source — so that data which can't possibly match is never read in the first place. This is one of the highest-leverage optimizations for large datasets, since I/O is usually the dominant cost of an analytical query.

## Why It Matters

Consider a query filtering a billion-row table down to a few thousand matching rows. Without pushdown, the engine reads and processes all billion rows before discarding most of them. With pushdown into a columnar file format, the engine can use per-block statistics to skip whole blocks that can't match, and skip fetching columns the query doesn't need at all.

## DuckDB's Pushdown into Parquet and Remote Files

DuckDB's optimizer pushes filter and projection predicates down into its scan operators. When scanning Parquet files, this means DuckDB checks each row group's footer statistics (min/max ranges) and Bloom filters before reading data, skipping row groups that can't match:

```sql
EXPLAIN SELECT customer_id, total
FROM read_parquet('s3://bucket/orders/*.parquet')
WHERE order_date = '2024-06-01';
```

The plan shows the filter applied at the `PARQUET_SCAN` step rather than as a separate operator afterward. When reading from remote storage via `httpfs`, pushdown becomes even more valuable: DuckDB only fetches the byte ranges it actually needs, reducing network transfer as well as local processing.
