Salesforce Admin Zero to Hero - Module 9: Schema & Data Modeling | SF Interview Pro
🗺️ Salesforce Admin Zero to Hero — Module 9 of 25
Schema & Data Modeling
Module 8 built individual objects. This module zooms out — Schema Builder, Many-to-Many relationships via junction objects, External IDs, and designing a complete, connected multi-object data model.
Module 9 of 25 · Phase 2: Data Model
🎯 What You Will Master in This Module
Module 8 gave you the building blocks — objects, fields, and one-to-many relationships. This module is about seeing and designing the WHOLE structure at once, including the one relationship pattern Module 8 deliberately left out: genuine Many-to-Many, which needs a structure of its own.
✓ Schema Builder — visualizing your entire data model as a connected diagram
✓ Many-to-Many relationships and Junction Objects — the pattern Lookup and Master-Detail alone cannot express
✓ External IDs — connecting Salesforce data to systems outside the platform
✓ Indexed fields and Large Data Volume (LDV) considerations
✓ Naming conventions and building a data dictionary
✓ Normalization vs a degree of denormalization — real trade-offs, not just theory
✓ Designing a complete, multi-object schema from a real business scenario
📋 In This Module
Concept 1 of 7
Schema Builder — Seeing the Whole Data Model at Once
Schema Builder is a visual, drag-and-drop canvas showing every selected object, its fields, and the relationship lines connecting them — a genuine Entity-Relationship Diagram generated live from your actual org metadata. It is the single best tool for understanding, communicating, and even building a data model, rather than piecing it together mentally from individual Object Manager pages.
⚡ Why This Matters
Understanding one object in isolation, as Module 8 focused on, is very different from understanding how 6 or 8 objects connect together as a system. Schema Builder makes relationship direction, cardinality, and overall structure immediately visible — exactly the kind of picture you would otherwise have to build manually on a whiteboard.
What Schema Builder shows for each object box:
+-----------------------------+
| Quality_Inspection__c |
+-------------------------------+
| Inspection_Date__c (Date) |
| Result__c (Picklist)|
| Total_Defects__c (Roll-Up) |
+-----------------------------+
↑
| Master-Detail
|
+-----------------------------+
| Inspection_Line_Item__c |
+-----------------------------+
Lines between boxes show relationship type and direction —
exactly the diagram style used throughout this course's own
diagram boxes, but generated live from your real org.
🛠️ Hands-On: Explore Your Module 8 Objects in Schema Builder
1Setup → Quick Find → Schema Builder → click it
2In the left panel, uncheck all Standard Objects, then check Quality Inspection and Inspection Line Item from your Module 8 work.
3Observe the canvas — confirm the Master-Detail relationship line correctly shows direction from child to parent.
4Click directly on the Quality_Inspection__c box → note you can see every field listed inside it, without navigating back to Object Manager.
5Try adding a new field directly from Schema Builder by clicking + Add Field in the toolbar and dragging it onto an object box — this is a fully functional alternative to Object Manager's field creation flow, not just a read-only diagram.
💡 Schema Builder Is Also a Communication Tool
Beyond personal use, Schema Builder diagrams are genuinely useful to export (via the Print button) and share with stakeholders, developers, or documentation — a visual data model communicates structure far faster than a written description ever could, especially when explaining a design decision to someone non-technical.
Concept 2 of 7
Many-to-Many Relationships via Junction Objects
Module 8 covered Lookup (loose one-to-many) and Master-Detail (tight one-to-many). Neither natively supports genuine Many-to-Many — where many records of Object A can relate to many records of Object B simultaneously. Salesforce solves this with a Junction Object: a custom object with TWO Master-Detail relationships, one to each side of the many-to-many pair.
⚡ Why This Matters
Many-to-Many is an extremely common real-world pattern — students enrolled in multiple courses, vendors supplying multiple products, employees working on multiple projects. Without understanding Junction Objects, an Admin might try to force this pattern into a single Lookup field, which cannot actually represent "many-to-many" at all.
Real example: Vendors and Products (many-to-many)
Vendor__c Product2 (standard)
| |
| Master-Detail Master-Detail
| |
+------ Vendor_Product__c ------+
(the JUNCTION OBJECT)
Fields: Supply_Price__c,
Lead_Time_Days__c
One Vendor can supply MANY Products.
One Product can be supplied by MANY Vendors.
The Junction Object holds one row per Vendor-Product PAIR,
plus any fields specific to that specific pairing
(like a price that varies by which vendor supplies it).
🛠️ Hands-On: Build a Genuine Many-to-Many Relationship
1Setup → Object Manager → Create → Custom Object → Label
Vendor, Plural Vendors → Save.2Create a second Custom Object → Label
Vendor Product, Plural Vendor Products → this will be the Junction Object.3On Vendor Product, create a Master-Detail relationship to Vendor.
4On Vendor Product, create a SECOND Master-Detail relationship, this time to Product2 (the standard Product object).
5Add a
Supply Price Currency field directly on Vendor Product — this field is specific to the PAIRING, not to either Vendor or Product alone.6Create one Vendor, one Product, and one Vendor Product record linking them with a specific price → then create a SECOND Vendor Product record linking the SAME Product to a DIFFERENT Vendor at a different price, proving true many-to-many.
⚠️ Common Gotcha — A Custom Object Can Only Have Two Master-Detail Relationships Maximum
Salesforce limits a single object to a maximum of two Master-Detail relationships — which is exactly the number a standard Junction Object needs, but leaves no room for a third. If a design genuinely seems to need three-way many-to-many relationships, this typically requires a different pattern, such as one Master-Detail plus Lookups, or restructuring the model, since a single object cannot be Master-Detail child to three different parents simultaneously.
Concept 3 of 7
External IDs — Connecting Salesforce to the Outside World
An External ID field is a custom field flagged with the "External ID" attribute, holding a unique identifier from a SYSTEM OUTSIDE Salesforce — an ERP system, a legacy database, or (relevant to Anant's own work) Business Central. External IDs are what make reliable, repeatable data integration and UPSERT operations possible, rather than relying on Salesforce's own internal Record ID alone.
⚡ Why This Matters
When integrating Salesforce with an external system — like a Salesforce-to-Business-Central integration — the external system does not know or care about Salesforce's internal Record IDs. External ID fields let both systems agree on a shared reference point, enabling clean UPSERT logic: "update this record if a match on External ID already exists, otherwise create a new one."
| Field Setting | What It Enables |
|---|---|
| External ID | Marks this field as a reference to an external system's identifier — enables UPSERT matching |
| Unique | Prevents duplicate values in this field across all records — often paired with External ID |
| Case Sensitive (if Unique) | Determines whether "ABC123" and "abc123" are treated as the same value or different values for uniqueness checking |
🛠️ Hands-On: Create an External ID Field
1Setup → Object Manager → Vendor (from Concept 2) → Fields & Relationships → New
2Create a Text field, Label
BC Vendor Code, API Name auto-populates as BC_Vendor_Code__c.3Check External ID and Unique. Set Unique matching to
Case sensitive.4Save, adding it to the page layout.
5Conceptually: this field now lets an external integration (like a Business Central sync job) reliably match an incoming record to the correct existing Vendor in Salesforce, using Business Central's own vendor code rather than any Salesforce-internal ID.
💡 External IDs Are Central to Data Loader UPSERT Operations
Module 10 covers Data Loader in depth, but the connection is worth previewing here: Data Loader's UPSERT operation specifically requires an External ID field to determine whether an incoming row should update an existing record or insert a new one. Without a properly configured External ID, repeatable, safe bulk data loads from external systems become significantly harder to manage correctly.
Concept 4 of 7
Indexed Fields & Large Data Volume Considerations
As an object accumulates millions of records — a genuine Large Data Volume, or LDV, scenario — query and search performance depends heavily on whether the fields being filtered or searched on are INDEXED. Salesforce automatically indexes certain fields by default, and allows custom indexes to be requested for others, but this becomes a real design consideration only once data volume grows significantly.
⚡ Why This Matters
A report or SOQL query filtering on a non-indexed field across millions of records can be dramatically slower than the same query filtering on an indexed field — sometimes the difference between a query completing normally and one that times out entirely. This becomes especially relevant for any Admin working with genuinely large datasets, like extensive customer or transaction history.
| Automatically Indexed by Default | Can Request Custom Indexing |
|---|---|
| Record ID, Name, Owner, CreatedDate, LastModifiedDate | Any custom field marked External ID or Unique automatically gets indexed |
| Lookup and Master-Detail relationship fields | Other frequently-filtered custom fields, via a Salesforce Support case for Custom Indexes |
🛠️ Hands-On: Identify Indexing on Your Own Fields (Conceptual)
1Recall your
BC Vendor Code field from Concept 3 — because you checked External ID and Unique, this field is automatically indexed by Salesforce, with zero extra configuration needed.2Consider your
Result picklist field on Quality Inspection from Module 8 — this is NOT automatically indexed. In a small Dev Org this has no noticeable effect, but in an org with millions of Quality Inspection records, frequent filtering on Result alone could become a genuine performance concern.3Setup → Quick Find → Optimizer (if available in your edition) — this tool can surface data volume and performance-related recommendations for a real production org, including indexing suggestions.
⚠️ Common Gotcha — Indexing Is Not Something You Toggle Freely Yourself
Unlike most settings covered in this course, requesting a Custom Index on a standard (non-Unique, non-External-ID) field typically requires opening a Salesforce Support case — it is not a simple checkbox an Admin can flip in Setup. This is worth knowing precisely so you do not spend time hunting for a self-service indexing option that does not exist for arbitrary fields.
Concept 5 of 7
Naming Conventions & Building a Data Dictionary
A Data Dictionary is a maintained reference document listing every object and field, its purpose, its type, and its relationships — essentially documentation of your entire schema in one place. Consistent naming conventions across objects and fields make this documentation, and the schema itself, dramatically easier to navigate as an org grows.
⚡ Why This Matters
A year into a growing implementation, nobody remembers why a field called
Status_2__c exists or how it differs from Status__c. Consistent naming and living documentation are what let a NEW Admin — or the same Admin returning after months away — understand the schema quickly, rather than reverse-engineering it field by field.| Convention | Example |
|---|---|
| Descriptive, unambiguous field labels | Vendor Supply Price, not Price 2 or Amt |
| Consistent prefixing for related fields | Inspection_Date__c, Inspection_Result__c, Inspection_Notes__c — grouped visually |
| Avoid ambiguous abbreviations | Batch_Reference__c, not Bat_Ref__c |
| Document the WHY, not just the WHAT | A data dictionary entry noting "added for BC integration matching" is far more useful than the field name alone |
🛠️ Hands-On: Start a Simple Data Dictionary
1Open a spreadsheet (or use the xlsx skill in a real work context) and create three columns: Object, Field, Purpose.
2Document every custom field you have built across this course so far — Quality_Inspection__c's fields, Vendor__c's fields, Vendor_Product__c's fields.
3For each, write one clear sentence on WHY it exists — e.g. "BC_Vendor_Code__c: External ID matching Business Central vendor records during integration sync."
4This is not busywork — real Admin roles maintaining Salesforce-to-external-system integrations rely on exactly this kind of document to onboard new team members and troubleshoot integration mapping issues quickly.
💡 Schema Builder's Print Export Feeds Directly Into Documentation
Combining Concept 1's Schema Builder diagram export with a written Data Dictionary gives a genuinely complete data model reference — visual structure plus written purpose for each piece. Many mature Salesforce implementations maintain both side by side as living documentation, updated whenever the schema changes.
Concept 6 of 7
Normalization vs a Practical Degree of Denormalization
Normalization — splitting data into many small, non-redundant related tables — is classic relational database best practice. Salesforce's own standard model is reasonably normalized (Account/Contact/Opportunity as distinct objects), but real Admin design work often involves a genuine trade-off: how many separate child objects is actually the RIGHT number, versus when a few extra fields directly on a parent are simpler and perform better.
⚡ Why This Matters
Over-normalizing a Salesforce schema — splitting everything into maximally granular objects — can create excessive related lists, more complex reports (more joins needed), and more Roll-Up Summary Fields just to reassemble a simple picture. Under-normalizing creates duplicate data and awkward multi-value fields. The right balance is a genuine design judgment call, not a fixed rule.
Over-normalized example (too granular):
Vendor__c → Vendor_Address__c → Vendor_Address_Line__c
(three objects just to capture one company's mailing address)
Reasonably balanced:
Vendor__c with Street__c, City__c, State__c, Postal_Code__c
directly on the Vendor record itself
(an address is not usually a genuinely separate "entity")
Under-normalized example (data duplicated):
Vendor__c has a Text field "Products_Supplied__c" listing
product names as a comma-separated string
(no real relationship, no reporting integrity, prone to typos)
The Vendor_Product__c junction object from Concept 2 is the
correctly balanced solution for the many-to-many case specifically.
🛠️ Hands-On: Evaluate Your Own Design Choices
1Look back at your Vendor object from Concept 2 — if you added a mailing address, ask: does this need to be its own object, or are simple fields directly on Vendor sufficient? For a single address per Vendor, fields directly on Vendor are usually the right, simpler call.
2Now consider: if a Vendor could have MULTIPLE addresses (billing, shipping, manufacturing), a separate Vendor_Address__c child object (one-to-many) would become the right choice instead — the deciding factor is cardinality, not a fixed rule about addresses in general.
3This exercise — asking "does this genuinely need to be its own object, given how many of these can exist per parent" — is the practical judgment call behind every normalization decision you will make as an Admin.
⚠️ Common Gotcha — Comma-Separated Text Fields Are a Design Smell
A Text field storing multiple comma-separated values (like a list of product names crammed into one field) is almost always a sign that a proper relationship — Lookup, Master-Detail, or a Junction Object — should have been used instead. This pattern breaks reporting (cannot filter or group cleanly), breaks data integrity (typos, inconsistent formatting), and should be treated as a clear signal to revisit the relationship design.
Concept 7 of 7
Designing a Complete Multi-Object Schema
This final concept combines everything from Modules 8 and 9 into one end-to-end design exercise — taking a realistic, moderately complex business scenario and producing a complete schema: objects, relationship types (including a genuine many-to-many), key fields, and an External ID for integration.
⚡ Why This Matters
This is exactly the scope of design question a senior Admin or Solution Architect interview presents — not "what is a Lookup relationship" in isolation, but "design a data model for this scenario," requiring you to apply every concept from both data modeling modules together, under realistic constraints.
Scenario: "We run training courses. Each course has multiple
sessions on different dates. Employees can enroll in multiple
courses, and we need to track attendance per session, plus sync
course completion data with our external LMS system."
Resulting schema:
Course__c (Master-Detail child: Course_Session__c)
|
+-- Course_Session__c (one row per date/session)
|
+-- Attendance__c (JUNCTION between
Course_Session__c and a Contact/User,
tracking one attendance record per person
per session)
Course__c also gets: LMS_Course_ID__c (External ID, Unique)
for syncing completion data with the external LMS system.
🛠️ Hands-On: Build This Schema in Schema Builder
1Create
Course__c with an LMS_Course_ID__c External ID/Unique Text field.2Create
Course_Session__c as Master-Detail child of Course__c, with a Date field.3Create
Attendance__c as a Junction Object: Master-Detail to Course_Session__c, and a second relationship (Lookup, since Contact already has plenty of relationships — evaluate whether Master-Detail is even available) to Contact.4Open Schema Builder, select all three new objects plus Contact, and confirm the full diagram visually matches the scenario described — a genuine multi-object schema you designed and built entirely yourself.
⚠️ Module Wrap-Up — What Comes Next
You can now design and visualize complete, multi-object schemas, including the trickier Many-to-Many pattern and integration-ready External IDs. Module 10 shifts from DESIGNING the data model to actually MOVING data into and around it at scale — Data Loader, the Import Wizard, deduplication strategy, and the real-world data management practices an Admin uses on an ongoing basis.
💬 Module 9 Interview Questions (6)
Q1A business needs to track that many Vendors can each supply many different Products, with a price that varies by which specific Vendor supplies which specific Product. How do you model this, and why can't a simple Lookup field handle it?
This requires a Junction Object — a custom object with two Master-Detail relationships, one to Vendor and one to Product — where each record in the junction represents exactly one Vendor-Product pairing, and fields specific to that pairing, like the supply price, live directly on the junction object itself. A simple Lookup field cannot handle this because a Lookup field on either Vendor or Product can only reference ONE record on the other side per field — it has no way to represent that a single Vendor supplies multiple different Products, each potentially at a different price, without either duplicating Vendor records per Product or cramming multiple Product references into one field, neither of which properly represents genuine many-to-many data or supports clean reporting. The Junction Object pattern is Salesforce's standard, correct solution specifically because it creates one discrete record per relationship pairing, with room for pairing-specific fields like price.
"A Junction Object with two Master-Detail relationships, one to each side — a simple Lookup can only reference one record per field, so it structurally cannot express that one Vendor supplies many Products at potentially different prices; the Junction Object gives each Vendor-Product pairing its own record with its own pairing-specific fields."
Q2What is the maximum number of Master-Detail relationships a single custom object can have, and why does this limit matter for Junction Object design?
A single custom object can have a maximum of two Master-Detail relationships. This limit matters directly for Junction Object design because a standard Junction Object needs exactly two Master-Detail relationships — one to each side of the many-to-many pair — which fits perfectly within this limit, but leaves no room for a third. If a design scenario seems to call for a genuine three-way many-to-many relationship, a single Junction Object cannot express it directly, since it cannot be Master-Detail child to three different parent objects simultaneously; such a scenario typically requires restructuring into multiple two-way junction objects, or using a combination of one Master-Detail plus Lookup relationships depending on which side genuinely needs cascading delete and Roll-Up Summary behavior versus which side can tolerate a looser connection.
"Maximum two Master-Detail relationships per object — this fits a standard two-way Junction Object exactly, but means a genuine three-way many-to-many cannot be expressed by a single Junction Object and requires restructuring into multiple two-way junctions or a mix of Master-Detail and Lookup instead."
Q3Why is an External ID field important specifically for integration scenarios, and how does it relate to Data Loader's UPSERT operation?
An External ID field holds a unique identifier that originates from a system OUTSIDE Salesforce, giving both Salesforce and the external system a shared reference point that neither system's own internal record ID can provide on its own, since the external system has no knowledge of Salesforce's internal Record IDs and vice versa. This becomes essential for Data Loader's UPSERT operation specifically, because UPSERT needs a reliable way to determine whether an incoming row of data should UPDATE an existing Salesforce record or INSERT a brand new one — it does this by matching the incoming external identifier against the External ID field on existing records, updating on a match and inserting when no match is found. Without a properly configured, Unique External ID field, achieving this same reliable match-or-create behavior would require significantly more manual logic and would be far more prone to creating duplicate records during repeated integration syncs.
"External ID gives Salesforce and an outside system a shared reference point neither system's own internal ID can provide — Data Loader's UPSERT operation relies specifically on matching this field to decide update-existing versus insert-new, which is what makes repeatable, duplicate-safe integration syncs possible."
Q4An Admin notices that reports filtering on a specific custom picklist field are running very slowly once the object reached several million records. What is the likely underlying cause, and what are the realistic options to address it?
The likely underlying cause is that the custom picklist field is not indexed, meaning Salesforce must scan a much larger portion of the millions of existing records to satisfy the filter rather than using an efficient indexed lookup, which becomes a significant performance factor specifically at Large Data Volume scale, even though the same query would feel instantaneous on a small dataset. The realistic options are: first, if there is a legitimate business reason to make the field Unique or use it as an External ID, doing so would grant automatic indexing as a side effect, though this is not always appropriate depending on the field's actual purpose; second, and more commonly, the Admin can open a Salesforce Support case specifically requesting a Custom Index be added to that field, since arbitrary custom field indexing generally is not self-service; and third, reviewing whether the report or query design itself could be adjusted to filter on an already-indexed field, such as a Lookup relationship or CreatedDate, as a primary filter alongside the picklist as a secondary condition.
"Almost certainly the picklist field is not indexed, which only becomes a real performance factor at genuine Large Data Volume scale — realistic fixes are requesting a Custom Index via a Salesforce Support case, making the field Unique/External ID if that's genuinely appropriate, or redesigning the query to lead with an already-indexed field."
Q5What is the risk of using a comma-separated Text field to store a list of related values, such as product names a Vendor supplies, instead of a proper relationship structure?
Storing a list of related values as a comma-separated Text field breaks several things a proper relationship structure would otherwise provide. Reporting integrity suffers significantly, since Salesforce Reports cannot cleanly filter, group, or aggregate on individual values buried inside one larger text string, making it effectively impossible to answer a question like "which Vendors supply Product X" through standard reporting tools. Data integrity also suffers, since free-text entry is prone to inconsistent formatting, typos, and duplicate near-matches like "Silicone Sheet" versus "silicone sheet, " with no validation preventing these inconsistencies. This pattern is generally considered a clear design smell signaling that a proper Lookup, Master-Detail, or Junction Object relationship should have been used instead, since Salesforce's relational structure exists specifically to represent this kind of connected data reliably and reportably.
"Comma-separated Text fields break reporting integrity — you cannot cleanly filter or group on individual values buried in one string — and break data integrity through inconsistent free-text entry; this is a clear design smell indicating a proper relationship (Lookup, Master-Detail, or Junction Object) should have been used instead."
Q6Walk through how you would design the data model for: employees enrolling in multiple training courses, each course having multiple dated sessions, with attendance tracked per session and course completion synced to an external LMS.
The design starts with a Course custom object representing the training course itself, which needs an External ID field, such as an LMS Course ID, to enable reliable syncing of completion data with the external Learning Management System. Since each Course has multiple dated Sessions, and a Session cannot meaningfully exist without its parent Course, Course Session should be Master-Detail to Course, with a Date field capturing when that specific session occurs. Because attendance needs to be tracked per session AND an employee can attend multiple sessions across multiple courses, this is a genuine many-to-many relationship between Course Session and the person attending, requiring a Junction Object, Attendance, with a Master-Detail relationship to Course Session and a relationship to Contact or User representing the attendee, with each Attendance record representing one specific person's presence at one specific session. This complete structure — Course, Course Session as its Master-Detail child, and Attendance as the Junction Object connecting sessions to attendees — correctly represents every stated requirement using the relationship patterns covered throughout this module.
"Course (with an External ID for LMS sync) → Course Session as its Master-Detail child (one row per date) → Attendance as a Junction Object with Master-Detail to Course Session and a relationship to Contact/User, giving one record per person per session — correctly modeling the many-to-many attendance requirement while keeping LMS sync clean via the External ID."
📝 Module 9 Recap — Schema & Data Modeling Mastered
✅ Schema Builder visualizes your entire connected data model live from real org metadata — and can create fields directly, not just display them
✅ Many-to-Many relationships require a Junction Object with two Master-Detail relationships — a single Lookup field cannot express this pattern
✅ A custom object can have a maximum of two Master-Detail relationships — exactly enough for a standard Junction Object
✅ External ID + Unique fields enable reliable Data Loader UPSERT matching for external system integrations, and are automatically indexed
✅ Custom Indexing on arbitrary fields generally requires a Salesforce Support case — it is not a self-service checkbox
✅ Comma-separated Text fields storing lists are a design smell — they signal a proper relationship should have been used instead
✅ Normalization is a genuine trade-off, not a fixed rule — the right level of granularity depends on real cardinality, not theoretical purity
🎯 Module 9 Practical Checklist — Complete These in Your Org
1. Open Schema Builder and visualize your Module 8 custom objects together.
2. Build a genuine Many-to-Many relationship (Vendor/Product or similar) using a Junction Object with two Master-Detail relationships.
3. Add an External ID + Unique field to one object, simulating an integration key.
4. Start a simple Data Dictionary spreadsheet documenting every custom object and field built so far in this course.
5. Build the full Course/Course Session/Attendance schema from Concept 7 in Schema Builder.
Module 10 shifts from designing the data model to actually moving real data into it — Data Loader, the Import Wizard, deduplication, and ongoing data management practices.
2. Build a genuine Many-to-Many relationship (Vendor/Product or similar) using a Junction Object with two Master-Detail relationships.
3. Add an External ID + Unique field to one object, simulating an integration key.
4. Start a simple Data Dictionary spreadsheet documenting every custom object and field built so far in this course.
5. Build the full Course/Course Session/Attendance schema from Concept 7 in Schema Builder.
Module 10 shifts from designing the data model to actually moving real data into it — Data Loader, the Import Wizard, deduplication, and ongoing data management practices.
Test yourself on this topic
2,244 practice MCQs across 27 quizzes — 5 quizzes free, no signup
RK
Written by
Rajnish Kumar
Salesforce Developer · Apex, LWC, Data Cloud & AI · Building SF Interview Pro
Keep Preparing
Practice with real people
Join the free Mock Interview Community — practice with peers, get honest feedback, and walk into your real interview confident.
Join the Community ↗