DEV Community

Rohan Mehta
Rohan Mehta

Posted on

Salesforce SOQL: 7 Practices That Keep Your Queries Fast and Governor-Limit Safe

Salesforce SOQL: 7 Practices That Keep Your Queries Fast and Governor-Limit Safe

By Rohan Mehta, Salesforce writer at Way2Force

SOQL looks simple — until a query that works fine in a sandbox blows up in production with too many rows, too many queries, or a timeout nobody can explain. The difference is rarely the data. It is how the query was written, where it runs, and what it asks for.

Here are seven practices that keep SOQL fast, predictable, and safe under Salesforce's governor limits.

1. Query only the fields you actually use

SELECT Id, Name FROM Account is almost always better than pulling every field on the object. Extra fields cost heap, slow down serialization, and make the code harder to reason about. If a field is not used downstream, leave it out. This is the cheapest performance win in all of Apex.

2. Never put SOQL inside a loop

This is the classic governor-limit trap. A query inside a for loop works for one record and fails at 101. Collect the IDs first, run one query outside the loop, and map the results by ID. The same rule applies to DML: bulkify first, always.

Good code for bulk data starts with good data habits — before you import anything, work through a migration checklist so the records you query later are clean. Our guide to data cleaning before AI and automation work makes the same point from the admin side: messy input produces messy output, in queries as well as reports.

3. Filter on indexed fields where possible

Id, Name, OwnerId, CreatedDate, and lookup fields are indexed by default, and Salesforce can use custom indexes too. A selective WHERE clause on an indexed field lets the query engine skip most of the table instead of scanning it. If a query on a large object is slow, check selectivity before you rewrite the logic.

4. Use bind variables, not string concatenation

Bind variables (WHERE Id IN :accountIds) are safer and easier to read than building query strings by hand, and they protect you from injection-style bugs. Reserve dynamic SOQL for the cases that truly need it — a genuinely variable field list or object — and keep the rest static and typed.

5. Respect the 50,000-row limit — design for it

SOQL returns at most 50,000 rows per transaction. If your logic can plausibly exceed that, you need a different shape: tighter filters, aggregate queries, Batch Apex, or pagination. Do not discover the limit in production. When you are testing, use realistic data volumes, not three sample records — the same discipline that matters when you write Apex test classes that actually help.

6. Prefer aggregate queries for counts and sums

If you only need a count, a sum, or a grouped total, let the database do it: SELECT COUNT(Id), StageName FROM Opportunity GROUP BY StageName. Pulling thousands of records into Apex just to count them wastes heap, CPU time, and query rows. Aggregate results are also much easier to hand to a report or dashboard.

7. Test queries in the Query Editor before you code them

The Developer Console's Query Editor shows row counts, execution behaviour, and errors before a single line of Apex is written. A five-minute check there saves an hour of debugging a deployed trigger. It is also the fastest way to confirm a field name, a relationship name, or a filter actually behaves the way you assumed.

The habit that ties it together

Fast SOQL is not about clever syntax. It is a habit: filter selectively, bulkify relentlessly, ask the database for exactly what you need, and test with realistic volumes. Teams that follow those four habits rarely hit governor limits — and when they do, the fix is usually obvious because the query is already small and readable.


Originally published at Way2Force — practical guides on Salesforce Flow, automation, and CRM, by Rohan Mehta, Salesforce writer at Way2Force.

Top comments (0)