SOQL vs SOSL in Salesforce
Two query languages, two different jobs: one retrieves structured records, the other runs a text search across objects. Here is exactly when to reach for each.
Use SOQL when you know which object holds the data and want to retrieve or filter its records precisely. Use SOSL when you need a text search across many fields or objects at once and don’t know exactly where the match lives. SOQL queries the database like a SELECT; SOSL searches the search index with FIND.
SOQL vs SOSL: What Each Language Actually Does
Salesforce ships two languages for reading data, and the choice between them is not stylistic — it changes what you can search, how results come back, and which governor limits apply. A SOQL (Salesforce Object Query Language) query is the equivalent of a SQL SELECT statement: it searches the org’s database for records in objects you name explicitly. A SOSL (Salesforce Object Search Language) query is a programmatic text-based search that runs against the search index rather than the live database.
That distinction drives everything else. Because SOQL reads the database directly, it returns exact matches on any field type — numbers, dates, checkboxes, picklists — and supports precise WHERE filtering, relationship traversal, sorting, aggregation, and record counts. Because SOSL reads a pre-built index, it only searches text, email, and phone fields, but it can scan those fields across many objects — related or not — in a single call and return ranked matches.
SOQL
Structured Query- Starts with
SELECT, uses aWHEREclause - Queries one object (plus its relationships)
- Searches any field type, returns exact matches
- Supports
ORDER BY,GROUP BY,COUNT() - Returns records (or an integer for counts)
SOSL
Text Search- Starts with
FIND, noWHEREclause - Searches many objects in one query
- Searches text, email, and phone fields only
- Uses the search index, returns ranked results
- Returns a list of lists, one per object type
When to Use SOQL vs SOSL
Ask one question first: do you already know which object the data lives in? If yes, reach for SOQL. Retrieving all Energy-industry accounts, counting open cases per owner, pulling a contact and its parent account, filtering opportunities by close date — these are structured problems with a known target object, and SOQL resolves them with exact filters and relationship queries.
Reach for SOSL when the target is a term rather than a record set. A global search box where a user types “Acme” and expects hits across accounts, contacts, leads, and cases is the classic SOSL use case — you don’t know in advance which object contains the match, and you want the search index to do the work. SOSL is also generally faster than SOQL for a CONTAINS-style text match, because the index tokenizes field values ahead of time. So a search for “John” against a field holding “Paul and John Company” surfaces quickly with SOSL.
If you find yourself running the same text search against several objects with multiple separate SOQL queries, collapse it into one SOSL query. A single SOSL FIND that returns three objects counts as one SOSL query — far cheaper than three SOQL queries against your per-transaction budget.
How SOQL and SOSL Differ in Apex
As the Apex Developer Guide’s SOQL and SOSL Queries reference shows, both languages are written inline inside square brackets, but they evaluate to different types. A SOQL statement returns a List<sObject>, a single sObject, or an Integer for a COUNT() query. A SOSL statement always returns a List<List<sObject>> — one inner list per object in the RETURNING clause, in the exact order you specified. If an object matches nothing, its inner list comes back empty rather than missing.
One more syntax trap worth knowing: in Apex the FIND search string is wrapped in single quotes (FIND 'Acme*'), but in the Query Editor and the SOAP/REST APIs it’s wrapped in braces (FIND {Acme*}). You cannot run DML directly on a SOSL result set — cast each inner list to its concrete type first, as shown above. If you’re troubleshooting query behavior, the Developer Console Query Editor runs both SOQL and SOSL interactively, and the sf data query CLI command supports both as well.
SOQL and SOSL Governor Limits
The two languages draw from separate governor-limit buckets, and mixing them up is a common exam trap. Per Apex transaction you get 100 SOQL queries (200 in asynchronous contexts) and can retrieve up to 50,000 records total across all SOQL queries. SOSL is tighter: 20 SOSL queries per transaction, and a single SOSL query returns at most 2,000 records across all objects combined. These limits are identical in synchronous and asynchronous Apex except for the 200-query SOQL ceiling.
One subtlety on the SOQL side, documented in Salesforce’s Execution Governors and Limits: a parent-child relationship subquery counts as an extra query, so queries with subqueries get a ceiling of three times the top-level number. For the mechanics of query limits, bulkification, and how the platform meters every operation, see the full breakdown of Apex governor limits.
Memorize the split: 100 SOQL queries / 50,000 SOQL records vs 20 SOSL queries / 2,000 SOSL records per transaction. Scenario questions love to hide a text search inside a loop across objects — the answer is almost always “consolidate into one SOSL query” to protect both the SOQL and SOSL budgets.
Enforcing Access on Queries
Both languages respect the security mode you run them in. Adding WITH USER_MODE to a SOQL or SOSL statement enforces the running user’s object permissions (CRUD), field-level security, and record-level sharing — a cleaner, more complete alternative to the older WITH SECURITY_ENFORCED clause. For dynamic queries, pass AccessLevel.USER_MODE to Database.query() or Search.query(). Whether a class runs queries in the caller’s sharing context is a separate lever — see how with sharing vs without sharing in Apex controls record visibility for the queries your code runs.
Quick Exam Recall
- Decision rule: Known object + precise filter → SOQL. Text term across unknown/many objects → SOSL.
- Return types: SOQL →
List<sObject>/ single /Integer; SOSL →List<List<sObject>>. - SOSL scope: text, email, and phone fields only — via the search index, not the database.
- Limits: 100 SOQL (200 async) / 50,000 rows; 20 SOSL / 2,000 rows per transaction.
Test your SOQL and SOSL instincts
Scenario questions on querying, governor limits, and Apex data access appear across the developer track.
Verified against the official Salesforce Winter ’27 SOQL and SOSL Reference, Apex Developer Guide, and Execution Governors and Limits. Study smarter at CertifySF.com.
