Reducing fields and filters in Views queriesfor Drupal 11 , 10 , 9 , and 8

Last updated :  

Caching (the last lesson) hides a slow query behind a fast copy. This lesson does something more fundamental: makes the query itself slow down less in the first place. A View that joins five tables and pulls thirty fields just to display a title and a date is like ordering the entire menu to make one sandwich — everything past what you actually use is pure waste, on every single cache miss.

What you'll learn in this lesson

  • Why every field and filter you add to a View becomes a real cost in the generated SQL
  • How to audit an existing View for fields nothing on the page actually uses
  • Why filtering early (in the query) beats filtering late (in a preprocess or Twig template)
  • How relationships and contextual filters can silently multiply query cost if used carelessly

Every field is a column in the SQL, whether you render it or not

It's easy to add a field to a View "just in case" — maybe you'll need the author's email later, maybe that extra taxonomy reference will be useful. Each one you add becomes an actual SELECT column (and sometimes an actual JOIN) in the query Views generates, whether or not your display ever prints it. A View with 4 genuinely-used fields and 8 "just in case" ones is running a query roughly three times heavier than it needs to be, on every single page load that isn't served from cache.

How to audit this in five minutes: open the View, click through its Fields list, and for each one ask "does the current template or field formatter actually output this?" Anything you can't immediately answer yes to is a candidate to remove. Views' own "Preview" pane at the bottom of the edit screen shows you the generated SQL directly — click it and read the actual query your field list produced.

Filter early, not late

A filter added to the View itself becomes a WHERE clause the database evaluates before rows are ever pulled into PHP. A filter you instead implement afterward — say, in a preprocess function that skips rows conditionally, or in Twig with an {% if %} — still made the database do the work of fetching and hydrating every row first, only to throw most of them away in PHP. Always push a filter as far left as it can go: View filter first, Views' own "Sort criteria" and "Contextual filters" next, and only fall back to post-processing when there's genuinely no way to express the condition as a query constraint.

Relationships and contextual filters: powerful, but not free

A relationship in Views (say, from a node to its author's user entity) becomes a real SQL JOIN. One relationship is usually fine; three or four chained together on a View that also has several filters can produce a query with enough joined tables that the database's own query planner starts struggling to pick a good execution plan. If a View feels unexpectedly slow, the Preview pane's generated SQL is the first place to look — count the JOINs before you look anywhere else.

Quick check: you have a View with a "Published" filter added as a Views filter criterion, and separately a Twig {% if node.isPublished %} check wrapped around the row markup "just to be safe." Is the Twig check helping performance? (No — by the time Twig runs, the database has already fetched every row, published or not. The Views-level filter already did the real work; the Twig check only adds a redundant per-row comparison in PHP, and if it's ever the *only* filter, it's actively worse, since unpublished rows still got fully queried.)

Key takeaways

  • Every field in a View's Fields list becomes a real SQL column — remove anything the display doesn't actually render.
  • Filter and sort in the View itself, not afterward in a preprocess function or Twig — that pushes the work to the database's WHERE clause instead of PHP.
  • Each relationship adds a real JOIN — check the Preview pane's generated SQL whenever a View feels slower than it should.
  • A "just in case" field or filter you never remove is a permanent tax on every uncached request to that View.

Coming up next

A lean query is only half the story on a View with a lot of rows — next we look at the pager itself, and a surprisingly common way it can quietly turn into its own performance problem on large datasets.