Table of Contents

Introduction
If you work with data in Salesforce, one thing becomes obvious pretty quickly — querying isn’t just another technical skill. It’s central to everything you build.
Early on, querying feels simple enough. You write a SELECT; pull some records and move on. That phase doesn’t last long. As systems grow, data volumes increase, relationships become more complex, and users expect faster responses. Data retrieval starts influencing performance in a very real way. Sometimes it even affects system stability.
You can usually spot developers who truly understand querying. They troubleshoot faster. Their logic feels cleaner. And they often prevent performance problems before they ever reach production. That’s rarely accidental — it comes from experience with how data behaves at scale.
The platform offers two main query languages to developers: SOQL & SOSL:
- SOQL — retrieves structured data from known objects
- SOSL — searches text across multiple objects
They sound similar, and beginners often treat them like they’re interchangeable. They aren’t. Each solves a different type of problem. Knowing when to use which one is a foundational skill — honestly, one of the skills that separates “working code” from “production-ready code.”
This guide walks through both — from basics to advanced usage — with a focus on how they behave in real implementations. Not just syntax, but performance, design decisions, and patterns you actually see in live environments.
How Data Is Structured
Before writing queries, it helps to understand how data is organized.
Everything lives in objects. If you come from a database background, think tables. That comparison holds up most of the time.
Each object contains:
- Fields — attributes describing the record
- Records — the stored data
- Relationships — connections between objects
Some standard objects appear almost everywhere:
- Account — companies or organizations
- Contact — individual people
- Opportunity — potential deals
- Case — support interactions
Here’s something many developers don’t fully appreciate at first: relationships matter more than individual objects.
Business data rarely exists in isolation. Accounts have contacts. Opportunities belong to accounts. Cases connect to customers. One record almost always leads to another — sometimes several.
So querying isn’t just retrieving rows. It’s navigating relationships. Once that idea settles in, the way you design queries changes quite a bit.
What SOQL Actually Does
SOQL retrieves structured data from objects.
If you know SQL, SOQL looks familiar — but there are differences. You don’t write manual joins. Relationships are built into the platform, and SOQL gives you specific ways to traverse them.
Typical structure:
SELECT fields
FROM object
WHERE condition
ORDER BY field
LIMIT number
Example:
SELECT Id, Name
FROM Account
WHERE Industry = 'Banking'
ORDER BY Name
LIMIT 10
Nothing complicated here. Most queries start simple.
But here’s something experience teaches — a query that works is not necessarily a query that scales. Pulling extra fields, skipping filters, or ignoring data size may not cause problems immediately. Later, though… it usually does. Often, when usage increases, or automation layers build up.
That’s why experienced developers evaluate queries through a performance lens, not just correctness.
Using SOQL in Apex
Most SOQL runs inside Apex code.
Example:
List<Account> accounts = [SELECT Id, Name FROM Account];
for (Account acc : accounts) {
System.debug(acc.Name);
}
Completely normal pattern.
But performance issues rarely appear when the data is small. They show up months later, when record counts grow, and business logic gets heavier. A lot of scalability problems come from code that worked perfectly during testing but wasn’t designed for growth.
Adhering to good practices from the very beginning saves a surprising amount of cleanup later.
Filtering as a Best Practice
Filtering records is one of the simplest — and most effective — performance improvements you can make.
Examples:
WHERE Industry = 'Banking'
WHERE CreatedDate = TODAY
WHERE AnnualRevenue > 1000000
WHERE Name LIKE 'Acme%'
Queries that pull entire large objects tend to get flagged in code reviews. And for good reason — they consume memory, slow processing, and make downstream logic heavier than it needs to be.
A practical rule many experienced developers follow:
If filtering is possible, apply it.
Even basic filtering helps more than people expect.
Working with Relationships

This is where SOQL becomes especially useful.
Child to Parent
Retrieve parent data from a child record using dot notation:
SELECT Name, Account.Name
FROM Contact
Very common pattern — especially in UI logic and reporting.
Parent to Child
Retrieve child records using a subquery:
SELECT Name,
(SELECT LastName FROM Contacts)
FROM Account
A sample code to iterate through parent and child(inner loop)
SOQL Query (Parent → Child)
List<Account> accountList = [
SELECT Name,
(SELECT LastName FROM Contacts)
FROM Account
];
So when you query from parent → child, Salesforce returns a collection (list) of child records. The relationship name reflects that — it’s plural. Think of it like this:
One Account → many Contacts
One Account → many Opportunities
One Account → many Cases
So the relationship names are:
Contacts
Opportunities
Cases
Not singular.
Iterating Parent and Child Records
for (Account acc : accountList) {
// Parent record
System.debug('Account Name: ' + acc.Name);
// Child records (inner loop)
for (Contact con : acc.Contacts) {
System.debug(' Contact Last Name: ' + con.LastName);
}
}
Why ‘Contacts’ and not ‘Contact’?
In Salesforce, the name you use in a parent-to-child subquery is not the object name. It’s the child relationship name. And child relationship names are usually plural. One Account can have many Contact records.
If you’re used to SQL joins, this syntax may feel a little unusual at first. But after building a few real features, it becomes second nature.
Parent → Child Query on Custom Objects
Now we want:
- All Projects
- And their related Tasks
SOQL:
SELECT Name,
(SELECT Name, Status_c FROM Tasks_r)
FROM Project__c
Notice:
Part Meaning
Project__c Parent object
Tasks__r Child relationship name
subquery Retrieves child records
Iterating Parent and Child (Apex Example)
List<Project__c> projects = [
SELECT Name,
(SELECT Name, Status_c FROM Tasks_r)
FROM Project__c
];
for (Project__c proj : projects) {
System.debug('Project: ' + proj.Name);
for (Task_c task : proj.Tasks_r) {
System.debug(' Task: ' + task.Name + ' Status: ' + task.Status__c);
}
}
Outer loop → parent
Inner loop → child records
Same pattern as standard objects.
Important Naming Rules for Custom Relationships
This is where developers make mistakes.
Custom object relationships follow these naming patterns:
Custom object: __c
Relationship field: __c
Child relationship name: __r
So:
Project__c : (object)
Task__c : (object)
Tasks__r : (relationship name used in subquery)
Notice the difference:
Objects → __c
Relationship navigation → __r
How to Find the Child Relationship Name (Very Important)
Never guess.
Here’s how to check:
Method 1 — Object Manager (Most common)
Go to Setup
Object Manager → Child object (e.g., Task__c)
Fields & Relationships
Open the lookup or master-detail field
Look for:
Child Relationship Name
That exact value is what SOQL uses.
Why SOQL in Loops Causes Problems
One of the most important Apex design rules:
Avoid running SOQL inside loops.
The platform enforces strict resource limits. If a query runs repeatedly inside a loop, you’ll eventually exceed limits. When that happens, execution stops immediately.
Example of what not to do:
for (Contact c : contactList) {
Account acc = [SELECT Name FROM Account WHERE Id = :c.AccountId];
}
Bulk-safe pattern:
Set<Id> accountIds = new Set<Id>();
for (Contact c : contactList) {
accountIds.add(c.AccountId);
}
Map<Id, Account> accountMap =
new Map<Id, Account>(
[SELECT Id, Name FROM Account WHERE Id IN :accountIds]
);
Governor Limits: The Real Constraint
Platform limits exist to keep everything stable.
Some key ones:
- Maximum 100 SOQL queries per transaction
- Maximum 50,000 records retrieved
- SOSL returns up to 2,000 results
If limits are exceeded, execution stops. No gradual slowdown — just failure.
Efficient querying isn’t optional. It’s required.
Pagination for Large Data Sets
Loading everything at once rarely makes sense.
Pagination retrieves records in smaller chunks:
SELECT Name
FROM Account
ORDER BY Name
LIMIT 20
OFFSET 40
Especially important in UI contexts. Development environments rarely reflect real user behavior — real data volume changes things quickly.
Preventing SOQL Injection
Dynamic queries introduce risk if not handled carefully.
Unsafe:
String query = 'SELECT Id FROM Account WHERE Name = ' + userInput;
Safe:
List<Account> accs = [
SELECT Id FROM Account WHERE Name = :userInput
];
Bind variables protect the query structure. Most teams enforce this pretty strictly — and they should.
Advanced SOQL Capabilities
Once the basics feel comfortable, more advanced features become useful.
Aggregates
SELECT COUNT(Id), SUM(Amount)
FROM Opportunity
WHERE StageName = 'Closed Won'
Great for analytics and reporting.
GROUP BY and HAVING
SELECT StageName, COUNT(Id)
FROM Opportunity
GROUP BY StageName
HAVING COUNT(Id) > 5
Helpful for identifying patterns in data.
Semi-Joins and Anti-Joins
Accounts with contacts:
SELECT Name
FROM Account
WHERE Id IN (SELECT AccountId FROM Contact)
Accounts without contacts:
SELECT Name
FROM Account
WHERE Id NOT IN (SELECT AccountId FROM Contact)
Very useful for data quality checks.
Polymorphic Relationships
SELECT Subject, Who.Name
FROM Task
Handles fields that can reference multiple object types.

Performance and Query Selectivity
As data grows, selectivity matters more.
Common optimization practices:
- Filter indexed fields
- Avoid leading wildcards
- Return only required fields
- Use selective conditions
Large implementations often analyze query plans — especially when data volumes get high. And they do get high.
Dynamic SOQL
Sometimes queries must be built at runtime.
String query = 'SELECT Id, Name FROM Account WHERE Industry = :industryValue';
List<Account> results = Database.query(query);
Flexible — but should be used carefully. Static queries are usually preferred.
What SOSL Is Designed For
SOQL retrieves structured data. SOSL performs keyword searches.
Example:
FIND 'Acme'
IN ALL FIELDS
RETURNING Account(Name), Contact(FirstName, LastName)
Common use cases:
- Global search
- Unknown record location
- Multi-object search
From a user perspective, SOSL behaves more like typical search functionality.
Search Index Behavior
SOSL relies on indexes that update shortly after records change.
That delay can confuse people during testing — newly created records might not appear immediately. That’s normal. Slightly annoying sometimes, but normal.
Search Scope Options
Example:
FIND 'john'
IN NAME FIELDS
RETURNING Contact(Name)
Limiting scope improves performance and relevance.
When SOSL Is Not the Right Tool
Avoid SOSL when:
- The object is known
- Precise filtering is required
- Structured retrieval is sufficient
SOQL handles most data retrieval needs. SOSL supports search scenarios.
Typical Usage Patterns
SOQL commonly supports:
- Business logic
- Validation
- Reporting
- Automation
SOSL typically supports:
- Global search
- Record lookup
- Customer support search tools
Testing Queries
Common testing methods:
- Developer Console
- Anonymous Apex
- Test classes
Larger implementations often include performance testing as well.
Common Mistakes
Frequently seen issues:
- Retrieving unnecessary fields
- Missing filters
- SOQL inside loops
- Weak input handling
- Overuse of dynamic queries
- Confusing SOQL and SOSL
Most teams run into these at some point. Some more than once.
Frequently Asked Questions (FAQ)
1. What is the difference between SOQL and SOSL?
SOQL retrieves structured data from one object. SOSL searches text across multiple objects.
2. Can SOQL update records?
No. SOQL is read-only. Use DML for updates.
3. What happens if governor limits are exceeded?
The transaction fails with a runtime exception.
4. How many relationship levels can be traversed?
Up to 5 levels upward (child to parent).
5. When should I use SOSL?
When building search functionality or searching across multiple objects.
Practice Exercises
Try implementing:
- Opportunity aggregation by stage
- Accounts without contacts
- Multi-object keyword search
- Converting unsafe dynamic queries
- Paginated record retrieval
Hands-on work builds understanding faster than reading alone. Always has.
Final Thoughts
Mastering SOQL and SOSL is a major step in becoming an effective developer.
Nearly every feature depends on efficient data retrieval — automation, reporting, integrations, user interfaces… everything connects back to data access.
A few guiding principles go a long way:
- Retrieve only what you need
- Filter deliberately
- Write bulk-safe logic
- Respect platform limits
- Secure user input
- Choose the right query tool
Most developers become comfortable with querying through repetition and real-world exposure. Over time, it stops feeling like syntax and starts feeling like structured problem-solving. And once that shift happens, things really do get easier.
If you want structured guidance, hands-on projects, and expert mentorship to truly master platform querying, certifications, and job-ready development skills, consider learning with AlmaMate. Their industry-focused training is the best Salesforce training in Noida & is designed to help you move beyond concepts and build the confidence to work on real implementations — the kind that employers actually look for. Start building practical experience today and take the next serious step in your developer journey.













