A backend engineer with six years of Node.js experience walked into an Oracle systems interview last year assuming it would look like any other backend loop: a two-sum warm-up, a system design whiteboard, a handful of behavioral questions. Twenty minutes in, the interviewer asked her to write a MERGE statement that would upsert rows into a slowly-changing dimension table, then explain what happens if two sessions run it against the same rows at the same moment. She had shipped years of production code sitting behind an ORM. She had almost never hand-written a MERGE, and it showed. Oracle's technical loops assume a level of direct SQL fluency that most companies built on Postgres and a query builder simply stopped testing for a decade ago.
Here's the bias most interview prep gets wrong about Oracle specifically: candidates spend their prep hours re-running generic array and string problems and skip the fact that Oracle is, underneath four decades of acquisitions, still fundamentally a database and enterprise software company. SQL remains one of the most used technologies among professional developers year after year, according to the Stack Overflow Developer Survey, and Oracle's interviewers lean on that assumption harder than most. A candidate who can reverse a linked list but freezes on an analytic window function or a basic execution plan question is going to have a rough forty-five minutes, no matter how many LeetCode problems they've cleared.
This page covers Oracle interview questions across eight areas: what the actual interview process and rounds look like, SQL and PL/SQL (still the backbone of most technical screens), Java fundamentals (Oracle has owned the language since acquiring Sun Microsystems in 2010), data structures and algorithms, system design, Oracle Cloud Infrastructure and cloud architecture, behavioral and culture-fit questions, and a handful of domain questions about how Oracle's business actually works. Questions are framed as representative of what candidates commonly report, not verbatim leaks.
What Oracle's interview process actually looks like
The shape of the loop varies more by business unit at Oracle than at most companies this size, since Database, OCI, and the Applications side (Fusion, NetSuite) hire somewhat independently.
Easy questions
15Most candidates go through a recruiter screen, one or two technical phone screens, and then a virtual loop of three to five back-to-back interviews covering coding, system design for more senior roles, and a conversation with the hiring manager. Onsite loops still happen for some roles based near Austin or Redwood Shores, but the majority of the process now runs over video. Entry-level and early-career hiring often compresses this into a single day of interviews instead of spreading it across weeks.
Mostly logistics and basic fit, not technical depth. The recruiter walks through your resume, confirms work authorization if it's relevant, asks why Oracle and why this specific team, and gives you a rough sense of the compensation band and timeline. Real technical evaluation starts in the next round, so don't over-prepare deep SQL trivia for this call and under-prepare a clear answer for why you're looking at Oracle in the first place.
Rarely, for most engineering roles. Almost all technical evaluation happens live, in a shared coding environment such as HackerRank, CoderPad, or an internal Oracle tool, during the phone screen or the loop itself. A handful of data science and applied ML postings occasionally include a short take-home case study, but across the much larger database, applications, and cloud engineering organizations, a live round is the norm.
Candidates commonly report three to six weeks, though it varies a lot by business unit. OCI and the core Database organization tend to move faster because they hire continuously against open headcount. Some Applications teams (Fusion, NetSuite) batch their loops around a specific project's staffing needs, and that can stretch closer to two months, especially around quarter-end when internal approvals slow down.
The cleanest version uses a subquery that excludes the maximum value first, then takes the maximum of what's left. It works in any SQL dialect and doesn't depend on a pagination clause that not every database supports the same way.
SELECT MAX(salary) AS second_highest
FROM employees
WHERE salary < (SELECT MAX(salary) FROM employees);Interviewers usually follow up asking what happens if the top salary is tied across two employees. This version handles that correctly, since it excludes the value, not a specific row, and both approaches (subquery versus a window function with DENSE_RANK) are worth having ready.
WHERE filters individual rows before any grouping happens, and it can't reference an aggregate function like SUM or COUNT. HAVING filters groups after GROUP BY has already collapsed rows together, and it's the only place you can filter on an aggregate result. A query that tries to put an aggregate condition in WHERE fails, because at the point WHERE runs, no aggregation has happened yet.
== compares references, whether two variables point at the exact same object in memory..equals() compares content, whether two String objects hold the same sequence of characters, even if they're different objects. Two strings created with the same literal often share a reference because of string interning, which makes == appear to work in casual testing right up until someone builds a string with new String(...) and the comparison silently breaks.
String a = "hello";
String b = "hello";
String c = new String("hello");
System.out.println(a == b); // true, both point at the interned literal
System.out.println(a == c); // false, c is a distinct object
System.out.println(a.equals(c)); // true, same contentAn abstract class can hold constructors, instance fields, and a mix of implemented and unimplemented methods, but a class can only extend one abstract class. An interface historically held only method signatures and constants, though since Java 8 it can also carry default and static methods with real implementations, and a class can implement as many interfaces as it needs. The practical rule of thumb: reach for an abstract class when subclasses share real state or behavior, and an interface when you're describing a capability multiple unrelated classes should support.
Walk the list once, keeping three pointers: the previous node, the current node, and a saved reference to the next node before you overwrite anything. At each step, point current's next back at previous, then shift all three pointers forward by one. It runs in O(n) time and O(1) extra space, since nothing gets copied, only the next pointers get redirected.
ListNode reverse(ListNode head) {
ListNode prev = null;
ListNode current = head;
while (current != null) {
ListNode next = current.next;
current.next = prev;
prev = current;
current = next;
}
return prev;
}The brute-force nested loop checks every pair in O(n squared) time. The better answer walks the array once, keeping a hash set of values already seen, and for each element checks whether target minus that element is already in the set. That gets you O(n) time at the cost of O(n) extra space, and it's the version interviewers actually want to see, since the naive one is easy but doesn't demonstrate much.
int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> seen = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
if (seen.containsKey(complement)) {
return new int[] { seen.get(complement), i };
}
seen.put(nums[i], i);
}
throw new IllegalArgumentException("No solution found");
}OCI is Oracle's public cloud platform, offering compute, storage, networking, and a range of managed services. Its clearest differentiator is how tightly it integrates with Oracle's own database and enterprise application stack, running Oracle Database, E-Business Suite, or Fusion Applications workloads that were already deeply invested in Oracle's ecosystem tends to be a more natural migration path onto OCI than lifting the same workload onto a generalist cloud built around a different set of assumptions.
A Virtual Cloud Network (VCN) is the overall private network you define inside OCI, with its own CIDR block, route tables, and security rules, roughly the OCI equivalent of a VPC on AWS. A subnet is a subdivision of that VCN's address space, and resources like compute instances get placed into a specific subnet, not directly into the VCN itself. Subnets are also where you decide public versus private reachability, since a subnet is marked as either allowing a public IP or restricted to private addressing only.
Interviewers are checking two things here: whether you can disagree professionally without either caving immediately or turning it into a standoff, and whether you actually followed through on the decision once it was made, even if it wasn't the one you argued for. A strong answer names a specific, real disagreement, explains the reasoning you brought to the conversation, and is honest about the outcome, including if the decision that was made turned out to be right, or wrong, in hindsight.
A generic answer about "innovation" or "growth opportunities" falls flat, since it could apply to any company in the industry. A stronger answer connects something specific, the scale of problems Oracle's database and cloud teams work on, a particular product area you've used or find genuinely interesting, the shift toward OCI and Autonomous Database, to your own background and what you actually want to be doing day to day. It's fine to be honest that comp and stability factored in too, as long as it's not the entire answer.
Pick something where you can speak to the tradeoffs you made, not just the final result. Interviewers get more signal from hearing you explain a decision you made under real constraints (a deadline, a legacy system you couldn't fully rewrite, incomplete requirements) than from a polished description of a feature that shipped cleanly. Being able to say what you'd do differently with hindsight is usually a stronger signal than pretending the project had no rough edges.
Medium questions
25Yes. Oracle's university and early-career hiring typically runs as a single combined day, sometimes called a Super Day, with several 30 to 45 minute interviews back-to-back instead of spread across separate weeks. It usually includes two data structures and algorithms rounds and one behavioral conversation, with no system design round, since that track is aimed at new graduates rather than candidates with production ownership experience.
A regular subquery runs once, independently, and its result gets used by the outer query. A correlated subquery references a column from the outer query, so it has to re-run once for every row the outer query touches. That makes correlated subqueries powerful for row-by-row comparisons but expensive on large tables, since the optimizer often can't rewrite them into a single-pass join the way it can with a plain subquery.
-- correlated: re-evaluated per row of e
SELECT e.name, e.salary
FROM employees e
WHERE e.salary > (
SELECT AVG(salary) FROM employees WHERE department_id = e.department_id
);All three are analytic functions that number rows within a partition, and they only differ in how they handle ties. ROW_NUMBER assigns a unique, sequential number regardless of ties, so two identical values still get different numbers. RANK gives tied rows the same number but then skips the next rank (1, 1, 3). DENSE_RANK gives tied rows the same number and doesn't skip anything (1, 1, 2).
SELECT name, salary,
RANK() OVER (ORDER BY salary DESC) AS rnk,
DENSE_RANK() OVER (ORDER BY salary DESC) AS dense_rnk,
ROW_NUMBER() OVER (ORDER BY salary DESC) AS row_num
FROM employees;MERGE compares a source dataset against a target table on a matching condition, then updates rows that already exist and inserts rows that don't, all in one statement. It's the standard tool for upserts, syncing a staging table into a warehouse dimension, reconciling a nightly batch feed against a live table, anywhere you'd otherwise write an existence check followed by a conditional insert or update.
MERGE INTO customers c
USING staging_customers s
ON (c.customer_id = s.customer_id)
WHEN MATCHED THEN
UPDATE SET c.email = s.email, c.updated_at = SYSDATE
WHEN NOT MATCHED THEN
INSERT (customer_id, email, updated_at)
VALUES (s.customer_id, s.email, SYSDATE);The follow-up worth preparing for: two sessions running MERGE against overlapping rows at the same time can hit a lock wait or, in rarer cases, an ORA-00001 unique constraint error if both sessions try to insert the same new key before either commits. Row-level locking protects you from a corrupted result, not from a session simply having to wait.
An implicit cursor is the one PL/SQL creates automatically for a plain SQL statement like an UPDATE or a single-row SELECT INTO, and you never declare it yourself. An explicit cursor is one you declare and control by hand, OPEN, FETCH, CLOSE, and it's what you reach for when a query returns multiple rows that you need to process one at a time in a loop.
DECLARE
CURSOR emp_cur IS SELECT name, salary FROM employees WHERE department_id = 10;
v_name employees.name%TYPE;
v_salary employees.salary%TYPE;
BEGIN
OPEN emp_cur;
LOOP
FETCH emp_cur INTO v_name, v_salary;
EXIT WHEN emp_cur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_name || ': ' || v_salary);
END LOOP;
CLOSE emp_cur;
END;An object becomes eligible once nothing reachable from a GC root, active thread stacks, static fields, JNI references, still points to it, directly or through a chain of other objects. The collector doesn't count references, it traces reachability from those roots, so two objects that only reference each other in a cycle but aren't reachable from anywhere else still get collected, unlike a naive reference-counting scheme.
Object a = new Object();
a = null; // no reachable reference left, eligible for collection on next GC cycleA checked exception (extending Exception, not RuntimeException) forces the caller to either catch it or declare it in a throws clause, so the compiler enforces that failure gets handled somewhere. An unchecked exception (extending RuntimeException) carries no such requirement, and it usually represents a programming error rather than an expected, recoverable condition.
Use a checked exception for a failure a caller genuinely needs to plan for, a file that might not exist, a network call that might time out. Use an unchecked exception for a bug in the code itself, an illegal argument, a null that should never have been null. Plenty of real production Java codebases lean unchecked almost everywhere now, since checked exceptions tend to spread try/catch boilerplate through call chains that have no meaningful way to recover anyway.
The contract requires that two objects considered equal by.equals() must return the same hashCode value. Override equals() without overriding hashCode() and you can end up with two objects that are equal but hash to different buckets, which silently breaks a HashMap or HashSet: you can put an entry in, then look it up with an equal key and get nothing back, because the lookup checked the wrong bucket entirely.
ArrayList backs onto a resizable array, so random access by index is constant time but inserting or removing from the middle requires shifting every element after it. LinkedList backs onto a doubly-linked chain of nodes, so inserting or removing at a known position is constant time but random access by index means walking the list from one end.
In practice, ArrayList wins the overwhelming majority of real cases, since most code reads far more than it inserts in the middle, and ArrayList's cache locality from contiguous memory makes it faster even for some insert-heavy workloads once you account for how CPUs actually access memory. LinkedList mostly earns its keep as a deque or when you're implementing something like an LRU cache by hand.
Floyd's cycle detection, also called the tortoise and hare approach: run two pointers through the list at different speeds, one advancing one node at a time, the other advancing two. If there's a cycle, the faster pointer eventually laps the slower one and they meet at the same node. If there's no cycle, the faster pointer simply reaches the end first. It runs in O(n) time and O(1) space, which is the entire point compared to the obvious hash-set-of-visited-nodes solution.
Make one pass to count how many times each character appears, using a hash map or a fixed-size array if you know the character set is limited (lowercase ASCII, for instance). Make a second pass over the string in its original order and return the first character whose count is exactly one. Two linear passes, O(n) time overall, and the second pass matters because a hash map doesn't preserve the string's original ordering on its own.
Count frequencies with a hash map in one pass, O(n). Then, rather than fully sorting all distinct elements by count, which costs O(n log n), use a min-heap of size k: push each element in, and whenever the heap exceeds size k, pop the smallest. What's left in the heap at the end is exactly the k most frequent elements, and this whole step costs O(n log k), which beats a full sort whenever k is meaningfully smaller than the number of distinct elements.
Most hash maps handle a collision, two keys hashing to the same bucket, either by chaining (each bucket holds a small list or tree of entries) or by open addressing (probing forward to the next free slot). Java's HashMap uses chaining, and since Java 8 it upgrades a bucket's chain to a balanced red-black tree once that bucket has enough entries, which caps worst-case lookup at O(log n) instead of O(n) for that pathological bucket. Without that upgrade, a hash map with a bad hash function or a deliberately crafted set of colliding keys degrades to O(n) lookups, effectively becoming a linked list.
Vertical scaling means adding more CPU, memory, or faster storage to a single machine. Horizontal scaling means adding more machines and spreading the load across them. Vertical scaling is simpler, since a database that isn't already built for distribution doesn't need any application-level changes to benefit from a bigger box, but it has a hard ceiling and a single point of failure.
For a genuinely database-heavy workload, vertical scaling on the primary is usually the right first move, since most relational databases aren't trivially horizontally scalable for writes, and only once you've hit a real ceiling does it make sense to reach for read replicas, sharding, or a distributed database, each of which trades simplicity for headroom.
Autonomous Database is a managed Oracle Database offering that automates patching, tuning, scaling, and backup, using machine learning to handle tasks a DBA would traditionally do by hand, adjusting resource allocation, applying security patches with no downtime window, optimizing query performance based on observed workload patterns. The problem it's solving is operational overhead: a huge share of the cost of running a database well isn't the license, it's the ongoing DBA time spent on routine maintenance, and Autonomous Database is Oracle's bet that most of that routine work can be automated away.
It lets a customer run Oracle Database services, including Exadata and Autonomous Database, physically inside Microsoft Azure's own data centers, managed through Azure's console, while Oracle operates the database infrastructure underneath. The practical benefit is for customers who've already built the rest of their stack on Azure but don't want to give up Oracle Database's specific capabilities or accept the network latency of calling out to a separate cloud for every database round trip. It's a direct answer to the fact that most large enterprises are multicloud whether they planned to be or not, and pretending otherwise costs Oracle deals.
A compartment is a logical grouping of cloud resources, a way to organize and isolate resources by project, environment, or team, similar in spirit to folders. An IAM policy is a separate statement that grants a specific group permission to take specific actions on resources within a specific compartment. Oracle keeps them separate so that organizational structure (where a resource lives) and access control (who can do what to it) can evolve independently, you can reorganize compartments without rewriting every policy, and you can tighten or loosen access without physically moving any resources.
The strongest version of this answer shows how you narrowed ambiguity rather than either guessing silently or blocking on getting every requirement fully specified before starting anything. Naming the specific assumptions you made explicit to stakeholders, and how you adjusted once real requirements landed partway through, demonstrates judgment under real constraints, which is exactly what this question is trying to surface.
Avoid a story where the stakeholder was simply unreasonable and you were simply right, since that rarely reads as self-aware. A better answer acknowledges what the stakeholder actually cared about underneath their difficult behavior, usually a legitimate concern expressed poorly, and walks through how you addressed that underlying concern rather than just managing the friction.
Interviewers want a real mistake, not a humble-brag disguised as a weakness. Own the actual impact honestly, then focus the majority of your answer on what changed afterward: a new check you added, a process gap you flagged to the team, a review step that didn't exist before. An answer that spends all its time on the mistake and none on the fix reads as someone who hasn't actually processed the lesson yet.
This is really a question about how you learn under time pressure, not about the specific technology. A concrete answer names what made the ramp-up hard (sparse documentation, no one on the team who'd used it before, a deadline that didn't leave room for a leisurely tutorial), and what you actually did, reading source code directly, finding one expert to ask targeted questions, building a small throwaway prototype before touching the real codebase.
A strong answer shows you pushed back with a concrete tradeoff, not just a general objection to more work. Naming the specific cost of the added scope, what it would delay, what corner it would force elsewhere, and proposing an alternative (cut this instead, or ship it in a second phase) reads as someone managing a real constraint, not someone just resistant to change.
A perpetual license is a one-time purchase (plus ongoing support fees) that a customer keeps indefinitely, running on their own infrastructure. A cloud subscription is a recurring payment tied to actual usage, running on Oracle's infrastructure. The switching cost calculus differs a lot between the two: a customer who's already sunk years of perpetual license spend and built deep operational expertise around an on-premises deployment faces a much higher bar to migrate than a customer already on a subscription model, where moving to a competing cloud provider is comparatively closer to a configuration change than a multi-year re-platforming project.
Fusion Applications is Oracle's enterprise resource planning suite built for large, complex organizations, deep customization, extensive integration options, and the operational depth big enterprises need. NetSuite, which Oracle acquired in 2016, targets small and mid-sized businesses with a simpler, more standardized cloud ERP that's faster to deploy and doesn't assume a large internal IT team to run it. Oracle keeps both because they serve genuinely different customer segments with different needs, not because of overlap it hasn't gotten around to resolving.
The honest answer isn't "Oracle is technically superior across the board," since Postgres handles a huge share of real-world workloads perfectly well. Oracle Database still wins on specific things: mature high-availability tooling built and tested over decades (Data Guard, RAC), enterprise support with contractual SLAs a regulated industry sometimes requires outright, advanced features like in-database analytics and partitioning at massive scale, and an existing organizational investment in Oracle skills and tooling that makes switching a real cost, not just a technical decision. For a genuinely greenfield system with no existing Oracle footprint and no regulatory requirement pushing toward it, plenty of teams reasonably choose Postgres and never look back.
Hard questions
6Every time PL/SQL hands a statement off to the SQL engine, it pays a context switch between the two engines, and a row-by-row loop pays that cost once per row. On a hundred-thousand-row table, that's a hundred thousand context switches instead of one. BULK COLLECT pulls an entire result set into a PL/SQL collection in a single fetch, and FORALL sends an entire batch of DML statements to the SQL engine in one round trip instead of one at a time.
DECLARE
TYPE id_tab IS TABLE OF employees.employee_id%TYPE;
v_ids id_tab;
BEGIN
SELECT employee_id BULK COLLECT INTO v_ids FROM employees WHERE department_id = 10;
FORALL i IN v_ids.FIRST..v_ids.LAST
UPDATE employees SET bonus = bonus * 1.1 WHERE employee_id = v_ids(i);
END;On real production batch jobs, this rewrite alone routinely takes an operation from minutes to seconds. Interviewers ask this one specifically because it separates a candidate who's read about PL/SQL performance from one who's had to actually fix a slow overnight job.
Run EXPLAIN PLAN FOR against the query, then read the plan from the innermost operation outward, since that's the order Oracle's cost-based optimizer actually executes in. The first thing worth checking is whether an index that used to get used dropped out of the plan, replaced by a full table scan, which usually points at stale statistics after a large data load, a change in bind variable values that shifted the optimizer's cardinality estimate, or a new index that got dropped or made invisible.
EXPLAIN PLAN FOR
SELECT * FROM orders WHERE customer_id = 12345 AND order_date > SYSDATE - 30;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);A close second cause: the optimizer's statistics simply went stale after a big batch load changed the table's row count and distribution, so gathering fresh stats with DBMS_STATS often fixes a regression that looks like a mysterious plan change but is really just outdated cardinality information.
The JVM first checks that the class is loaded and initialized, loading it via the classloader if this is the first time it's referenced. It then allocates memory for the object on the heap, sized based on the class's fields, zeroes that memory out to default values, runs the constructor (which itself may call a superclass constructor first), and finally returns a reference to the new object, which gets assigned to whatever variable is on the left side of the expression.
A detail that trips candidates up: field initializers and instance initializer blocks run in the order they're written in the source file, interleaved with the constructor body, not all before or all after it. Getting that ordering wrong is a common source of subtle bugs when a subclass constructor relies on a field the parent class hasn't finished setting up yet.
Yes. A memory leak in Java just means something is unintentionally still reachable, so the garbage collector correctly refuses to reclaim it, even though the application logically no longer needs it. The classic patterns: a static collection (a cache, a registry) that objects get added to but never removed from, a listener or callback registered on a long-lived object that never gets unregistered when the shorter-lived object it belongs to should be discarded, and unclosed resources like database connections or streams that hold native memory or file handles the GC has no visibility into at all.
static List<byte[]> cache = new ArrayList<>();
void handleRequest(byte[] data) {
cache.add(data); // never removed, grows forever, classic static-collection leak
}For a database that can't tolerate an extended outage, the standard approach uses Oracle GoldenGate or Data Guard to replicate changes continuously from the on-premises primary to a new OCI instance while the on-premises system stays live and serving production traffic. Once the OCI replica has caught up and stayed in sync for long enough to build confidence, the actual cutover becomes a brief maintenance window: stop writes, let the last few transactions replicate, redirect application traffic to the OCI instance, and resume.
The part that actually consumes most of the project's time isn't the data movement itself, it's validating that application behavior, connection strings, character set handling, any features tied to a specific on-premises configuration, all behave identically on OCI before the cutover happens, since a database migration that silently changes query performance characteristics is its own kind of outage even if the data arrives intact.
When license cost scales with the number of processor cores a database runs on, an engineering team sizing hardware isn't just optimizing for performance anymore, they're also optimizing for license cost, and those two goals don't always point the same direction. Over-provisioning cores for headroom that gets used one day a month means paying for licensed capacity that sits idle the other twenty-nine. Under-provisioning to save on license cost risks a performance cliff during peak load.
This is a big part of why virtualization and cloud sizing conversations around Oracle Database get more careful than they do for an open-source database with no per-core cost: a candidate who understands that core-based licensing shapes real infrastructure decisions, not just legal ones, is showing they've actually operated Oracle Database in a real environment rather than only read about its features.
Real-time scenario questions
6Start by picking an algorithm: token bucket is the common default, since it allows short bursts while still enforcing a steady average rate, versus a fixed window counter which is simpler but lets a client double its effective rate by hammering requests right at a window boundary. Store each client's bucket state in a fast shared store like Redis so the limit holds across multiple API server instances, not just per-instance, and decide upfront what happens when a client hits the limit: a 429 with a Retry-After header is the standard, honest answer.
The follow-up worth having ready: what happens if Redis itself goes down. A reasonable answer is to fail open (allow requests through) rather than fail closed (block everything), since an outage in your rate limiter shouldn't take down the entire API for every legitimate user.
The core problem is generating a short, unique key for each long URL and mapping the two directions. A base62-encoded auto-incrementing ID (or a counter service, since a single auto-increment column becomes a bottleneck at real scale) avoids collisions cleanly, versus hashing the URL and truncating, which needs a collision-handling strategy since two different URLs can hash to overlapping short codes.
Reads massively outnumber writes for this system, someone creates a short link once and it gets clicked thousands of times, so the design should lean into that: a cache in front of the database for the redirect lookup, and a database that's optimized for fast key lookups rather than complex joins, since the access pattern here is about as simple as key-value gets.
Put a message queue between the part of the system that decides a notification should go out and the part that actually sends it, so a slow or temporarily-down third-party provider (an SMS gateway having an outage, say) doesn't block the rest of the application. Each channel, email, SMS, push, gets its own worker consuming from the queue, retrying with backoff on transient failures, and routing to a dead-letter queue after enough failed attempts so a bad message doesn't retry forever.
Idempotency matters more here than it looks like at first: if a worker crashes after sending an SMS but before marking the job complete, a naive retry sends the same message twice. Deduplicating on a notification ID before sending, not just before enqueuing, is the detail that separates a working design from one that occasionally double-texts a customer.
Serialize with a pre-order traversal, writing each node's value, and writing an explicit sentinel (like "null" or "#") for every missing child instead of skipping it, since the sentinels are what let deserialization know exactly where each subtree ends without needing extra structural information.
String serialize(TreeNode root) {
if (root == null) return "#,";
return root.val + "," + serialize(root.left) + serialize(root.right);
}
int idx = 0;
TreeNode deserialize(String[] tokens) {
String token = tokens[idx++];
if (token.equals("#")) return null;
TreeNode node = new TreeNode(Integer.parseInt(token));
node.left = deserialize(tokens);
node.right = deserialize(tokens);
return node;
}Deserialization mirrors the same pre-order structure, consuming tokens one at a time and recursing left before right, which reconstructs the exact original tree shape because the sentinel values marked every leaf's boundary during serialization.
The standard shape is a primary database with one or more standby replicas kept in sync through continuous log shipping, so a standby can be promoted to primary quickly if the original fails. The real design decision is synchronous versus asynchronous replication: synchronous guarantees zero data loss on failover but adds write latency, since every write waits for the standby to confirm, while asynchronous keeps writes fast but risks losing the last few transactions that hadn't replicated yet if the primary dies at the wrong instant.
Detecting the failure correctly matters as much as the failover mechanism itself. A naive health check can trigger a false failover during a brief network blip, promoting a standby while the original primary is actually still healthy, which creates a split-brain scenario where two nodes both think they're primary. A real design needs a quorum-based decision, not a single health check, before it promotes anything.
There are three common isolation models, and the right one depends on how strict the data isolation requirement actually is. Silo (a fully separate database per tenant) gives the strongest isolation and the simplest security story but the worst infrastructure efficiency, since a tenant with almost no data still consumes a full database instance. Pool (all tenants share tables, filtered by a tenant_id column on every query) is the most efficient but puts real weight on getting row-level security right, since a single missing WHERE clause can leak one tenant's data into another's results. Bridge models put a shared database but separate schemas per tenant, splitting the difference.
For most SaaS products at real scale, the pool model with enforced row-level security, not just application-layer filtering that a future bug could bypass, is the pragmatic default. Larger enterprise customers with strict compliance requirements are the ones worth carving out into a dedicated silo, rather than building the entire system around the strictest tenant's requirements from day one.
How to prepare for an Oracle interview in 2026
Don't spend your entire prep budget on generic algorithm problems and skip SQL. Write a handful of real Oracle SQL and PL/SQL statements by hand, a MERGE, a query using an analytic window function, a bulk collect and forall rewrite of a row-by-row loop, and actually run them against a database, even a free Oracle XE instance locally, rather than just reading syntax. If the role touches OCI, spin up a compute instance and a VCN yourself once, since a candidate who's actually clicked through the console answers cloud architecture questions differently than one who's only read a diagram.
For roles closer to the Applications side, Fusion or NetSuite, get specific about which of Oracle's product lines the team actually works on before the interview, since a candidate who confuses the two in a behavioral answer about "why Oracle" signals they didn't do basic homework on the specific team they're interviewing with.
Get the reps in before the real thing
Explaining a MERGE statement or a BULK COLLECT rewrite on paper is different from defending it out loud when an interviewer changes one condition and asks what breaks. LastRoundAI's mock interview mode runs live coding and technical rounds with real-time follow-up questions in your browser, and the free plan includes 15 credits a month that reset monthly instead of piling up unused. Starter is $29/mo (or $19/mo on the 3-month plan) if a handful of sessions isn't enough runway.
Once your answers hold up under a follow-up, the slower part of the process is usually just getting in front of enough roles that actually match what you want to be interviewing for. Auto-Apply queues tailored applications for your review, 10 a month on the free plan, up to 400 a month on the Ultimate plan, and nothing goes out until you approve it.
Questions about either product go to contact@lastroundai.com. That's the only inbox we check.
How this list was built
Worth being straight about where these questions come from, because plenty of pages in this category are not. The set was compiled from a research pass across official documentation, vendor release notes, published engineering writing and public discussion of hiring processes, then cross-checked against the current version of each technology so nothing here describes behaviour that has since changed.
What that means in practice: these are the questions the material supports as reasonable and current for this role, not a transcript of any one company's loop. We have not sat in on your interview and we are not going to claim we have. Treat the list as well-sourced preparation rather than a leaked question bank, and expect your panel to phrase things their own way.
If you spot something out of date, tell us at contact@lastroundai.com and we will fix it.
Frequently asked questions
How long is the Oracle hiring process?
Often three to eight weeks end to end, with the gap between onsite and decision being the slowest part. Team matching, where it applies, can add further time and is not a reflection on your performance.
How many interview rounds does Oracle have?
Usually a recruiter screen, a technical phone screen, then an onsite loop of four to five rounds covering coding, system design and behavioural. The exact count shifts by level and team, and some loops add a domain-specific round, so ask your recruiter for the actual schedule.
How hard is the Oracle interview?
Hard, but the difficulty is more about depth of follow-up than exotic questions. Interviewers tend to take a reasonable problem and keep pushing on trade-offs, edge cases and what you would change at ten times the load. Preparing to be interrogated on an answer matters more than memorising more answers.
What coding level should I prepare for a Oracle interview?
Comfortable medium-difficulty problems solved cleanly while talking, rather than hard problems solved silently. Most rejections come from unclear communication and untested edge cases, not from failing to find an exotic algorithm.
Does Oracle ask system design at every level?
From mid-level upward, almost always, and it carries increasing weight as you go up. Junior loops may include a lighter version focused on structuring a feature rather than designing a distributed system.
