SOSL has a small surface area but real subtlety in performance tuning. Pick the right IN clause, scope the RETURNING list to the objects you actually need, add per-object filters to narrow results, and remember the index freshness lag when integrating with save-then-search patterns. Build queries in the Developer Console first to validate output before embedding in Apex or REST calls.
- Confirm SOSL is the right tool
Use SOSL when the search is text-based, spans multiple objects, or matches free-text content. Use SOQL when the query is field-precise on one object. A single-object exact-match search runs faster as SOQL on an indexed field.
- Open the Developer Console Query Editor
Setup > Developer Console > Query Editor > switch to SOSL mode. The editor provides syntax checking and instant execution. Use it to draft and refine the search expression and RETURNING clause.
- Write the FIND clause with the right search expression
Use curly braces for the search text: FIND {Acme}. Wildcards (*, ?) and phrase quotes work inside the braces. Use uppercase AND, OR, NOT to distinguish boolean operators from search terms.
- Pick the right IN clause
IN NAME FIELDS is fastest and right for global-search patterns. IN ALL FIELDS is broad and slow, use sparingly. IN PHONE FIELDS, IN EMAIL FIELDS narrow to those types when the search is type-specific.
- List the RETURNING objects with field lists
RETURNING Account(Id, Name), Contact(Id, FirstName, LastName). Each object gets its own field list. Add per-object WHERE clauses to filter results: Account(Id, Name WHERE Industry = ''Tech'').
- Test the query in the Developer Console
Run with Execute. Verify the result count per object, check that the search terms match expected records, and confirm performance is acceptable. Refine the search expression and IN clause as needed.
- Embed in Apex with proper result handling
List<List<SObject>> results = [FIND :searchTerm IN ALL FIELDS RETURNING Account(Id, Name)]. Bind variables prevent injection. Cast each nested list to the typed sObject array: (List<Account>) results[0].
- Handle empty results gracefully
Empty SOSL results return empty lists, not nulls. Check list size before iterating. Also handle the freshness-lag case if the search is downstream of a recent record save.
Determines which fields the search expression matches against. IN NAME FIELDS for global search, IN ALL FIELDS for broad search, narrower IN clauses for specific field types.
Lists the objects to search and fields to return. Scope to needed objects; broad lists slow the query down.
Optional filters inside RETURNING that narrow results per object. Useful for typeahead pickers that need both text match and relevance filtering.
- The search index updates asynchronously after each record save. Integrations that save a record and immediately search for it may not find the new record for several seconds.
- Wildcards at the start of a term (*Acme) are not allowed because the index cannot use them efficiently. Use trailing wildcards (Acme*) or exact-match search instead.
- SOSL queries cap at 2,000 records per object and 20,000 total across objects. Larger result sets are silently truncated. Tune the search to be more selective or paginate via the SOAP/REST search APIs.
- Short search terms (under three characters) often return no results because the index tokenizes content and short tokens do not produce useful matches.
- Apex SOSL counts against a separate 20-queries-per-transaction limit. Triggers that fire SOSL on every record save hit this fast on bulk operations.