Concepts
What you will learn: Choose a storage model when an application grows or needs predictable reads or differently connected data. Compare document, key-value, graph and other families, connecting the design to access patterns, distribution and consistency. The aim is a reasoned choice, not an assumption that is faster or -free.
Before you start: Relational databases organize data into tables and relationships; NoSQL models vary by engine. An access pattern is a question the application asks repeatedly, such as fetching a customer's orders. Start from that question; knowledge from topic 10 helps with comparison.
Select a term with a dotted underline for its meaning, then continue reading from the same place.
#Why NoSQL exists and its main families
Some workloads need predictable distributed access at scale, flexible aggregates or graph traversal rather than general joins. describes several families, not one product or a guarantee of -free design and superior speed.
| Family | Examples | Fit and cost |
|---|---|---|
| Document | MongoDB, Cosmos for NoSQL | Related data in documents; duplication and document growth need design |
| Key-value | Redis, DynamoDB | Known-key access; arbitrary queries are less natural. DynamoDB also supports document values |
| Wide-column | Cassandra | Partitioned rows and high write volume; query-driven tables and partition limits |
| Graph | Neo4j | Multi-hop relationships such as recommendations; not a universal reporting replacement |
| Search | Elasticsearch, OpenSearch | Full-text relevance and aggregations; indexing lag and shard overhead |
| Time-series | InfluxDB | Timestamped measurements, retention and downsampling; series matters |
| Vector | pgvector and vector features in multiple engines | similarity; approximate recall, filtering and embedding versions matter |
Families overlap. pgvector is a relational PostgreSQL extension, so vector search does not require a separate NoSQL store. Cassandra's wide-column model differs from analytical columnstores. Start with queries, consistency and operations rather than product fashion.
#Model by access patterns: orders and customers
If a screen always displays an order and its lines, one document is convenient. every order inside the customer creates unbounded growth and contention.
An order is an envelope containing its purchase-time invoice. CustomerId points to the current customer record; the invoice's shipping address remains a historical snapshot.
{
"id": "order-42",
"tenantId": "store-7",
"customerId": "customer-9",
"customerSnapshot": { "name": "Ali", "shippingCity": "Cairo" },
"status": "pending",
"lines": [
{ "productId": "product-3", "nameAtSale": "Mug", "qty": 2,
"unitPriceMinor": 12000, "currency": "EGP" }
],
"schemaVersion": 1
}
- List access patterns: order point lookup, time-ordered customer history and status changes. Design partition keys and indexes for them.
- Embed lines because they are bounded, order-owned and commonly accessed together. Reference products and customers with independent lifetimes.
- Snapshot purchase-time prices, names and shipping details; read current customer data separately when needed.
- If current facts are copied, define their owner, propagation mechanism and acceptable staleness.
Money uses minor units to avoid floating-point ambiguity; currency scales differ, so define the policy. Use schemaVersion, validation and readers that tolerate older documents. Flexible still requires schema design. Review product-specific document, array and contention limits.
#Partition keys, sharding and hot partitions
- Millions of customers' orders must be distributed across storage nodes. A partition key, such as CustomerId, determines their placement.
- That key localizes a customer's order queries, but one very large customer may overload its partition: a hot partition.
- List access patterns and customer-size distribution before choosing a key. Distributed data does not guarantee balanced load, and cross-partition queries have costs.
One machine has finite storage and . distributes data across nodes; the partition key routes reads and writes. A poor key can make a large cluster behave like one overloaded machine.
Access pattern Candidate key Risk
Orders for one ordinary tenant tenantId One huge tenant becomes hot
Order point lookups orderId Customer history fans out
Customer history tenantId + customerId One celebrity customer can be hot
Write-heavy event archive tenantId + time bucket Active bucket can still be hot
Extreme write skew key + hash bucket Reads must query several buckets
High helps but is insufficient: a million keys can still send most traffic to one value. Increasing range keys can concentrate writes on the newest shard. Hashing spreads writes but sacrifices range locality. Compound or hierarchical keys can balance needs where supported.
- Measure the busiest partition, not only averages, including RU, and throttling.
- Check routing: a query without its partition key may require scatter-gather.
- Review boundaries, uniqueness scope and resharding before choosing.
- If splitting tenants into buckets, design routing, result merging and migration.
#Replication and quorum reads and writes
A single copy is a failure point. improves availability and read locality, but coordinating replicas and ordering writes has costs.
| Pattern | Behavior | Trade-off |
|---|---|---|
| Leader/follower | Leader accepts writes and replicates them | Asynchronous followers may be stale; failover needs fencing and a durability policy |
| Multi-leader | Several regions accept writes | Conflict detection and resolution; last-write-wins can lose updates |
| Leaderless | Coordinators contact multiple replicas | Quorums, versions, read repair and anti-entropy; product details vary |
N = 3 replicas: A, B, C
W = 2: a successful write is acknowledged by A and B
R = 2: a read waits for responses from B and C
R + W = 4 > N: the read and write sets intersect at B
But: concurrent writes, version choice and failed writes still need rules.
R is the required read response count, W the write acknowledgement count, and N the replication factor. R + W > N guarantees intersection for quorums over the same fixed replica set. It does not alone guarantee linearizability. Version ordering, concurrent and partial writes, and membership changes still matter. Sloppy quorums may use fallback replicas and lose the expected intersection. Write- intersection itself requires 2W > N when needed; consensus involves more than this arithmetic.
W=1 reduces write waiting but can lose acknowledged data if failure precedes replication. Increasing R or W raises coordination and reduces tolerated failures for that operation. Never infer undocumented guarantees from a tuning setting alone.
#CAP and PACELC without slogans
If the network separates replica groups, should both continue serving operations or should one wait? describes a trade-off during a partition, not a permanent menu of two features.
During a partition:
C: preserve one-copy linearizable behavior, possibly reject or delay requests
A: every request to a non-failing node completes, possibly with stale results
PACELC:
If Partition: Availability versus Consistency
Else: Latency versus Consistency
C means linearizability, not consistency as valid constraints. A is formal availability for every request to a non-failing node, not ordinary uptime percentage. Network partitions must be handled rather than selecting away P. One product may make different choices by operation or configuration.
Two disconnected store branches cannot both promise the last item safely without coordination. Refusing one reservation preserves the but reduces availability for that operation.
also reminds us that even healthy networks impose when waiting for distant replicas. Avoid labeling every feature of a product AP or CP without naming scope and configuration.
#Consistency levels through Cosmos DB
A customer updates an address and immediately reads an older value. Saying eventual alone does not define the user experience. Choose a precise guarantee and scope.
| Level | Guarantee | Fit |
|---|---|---|
| Strong | Linearizable reads of the latest committed write in the system's order | Decisions requiring current state; coordination and availability/ costs |
| Bounded staleness | Lag bounded by configured versions or time | Explicitly bounded rather than unrestricted stale reads |
| Session | Read-your-writes and monotonic reads within a session using appropriate | Users see their changes; not global latest for everyone |
| Consistent prefix | Visible writes preserve order without gaps in the visible prefix | Older but ordered observations |
| Eventual | Convergence after writes cease and updates propagate, without a guaranteed lag bound | Read models that tolerate staleness |
This uses Cosmos for terminology; check other mappings and partition and scope. Propagate session tokens when a user moves between application instances. A reused client helps token management but does not cover every distributed flow. The account default normally bounds request-level consistency; requesting strong on an eventual account is not a magical upgrade.
#BASE, ACID and NoSQL transactions
A nonrelational model does not prohibit . Scope and cost are the key differences. commonly means Basically Available, Soft state and ; it is not a precise specification of every behavior.
// MongoDB.Driver; reuse client. Replica set or supported sharded deployment required.
using var session = await client.StartSessionAsync(cancellationToken: ct);
await session.WithTransactionAsync(async (s, token) => // (1)
{
var filter = Builders<StockDocument>.Filter.And(
Builders<StockDocument>.Filter.Eq(p => p.Id, productId),
Builders<StockDocument>.Filter.Gte(p => p.Available, quantity));
var update = Builders<StockDocument>.Update.Inc(p => p.Available, -quantity);
var result = await stock.UpdateOneAsync(s, filter, update,
cancellationToken: token); // (2)
if (result.ModifiedCount != 1)
throw new InvalidOperationException("Insufficient stock");
await orders.InsertOneAsync(s, order, cancellationToken: token);
return order.Id; // (3)
}, cancellationToken: ct);
- (1) Operations share a session. The helper may retry the callback for transient failures, so avoid external side effects and do not swallow exceptions.
- (2) Validate positive quantity beforehand. The conditional update and transaction connect stock to order creation; pass the session to every call.
- (3) A stable order identifier created outside the callback helps outcome handling. Do not run parallel operations in one transaction. Prepared StockDocument and OrderDocument collections are assumed.
| Product | Important boundaries |
|---|---|
| MongoDB | Atomic single-document writes; multi-document transactions on supported deployments with appropriate concerns and coordination costs |
| DynamoDB | TransactWriteItems atomically changes up to 100 distinct items in one account and Region, within service size limits; not BatchWriteItem |
| Cosmos for | Transactional batches share one logical partition and container, not arbitrary cross-partition transactions |
transactions can coexist with eventual replica reads. Money and stock usually need conditional writes, version checks or explicit transactions rather than last-write-wins. Never assume every NoSQL transaction has identical relational semantics.
#MongoDB indexing and query plans
A document model does not eliminate collection scans. Index actual filters and sorting rather than letting flexible schemas hide a bottleneck.
using MongoDB.Driver;
var keys = Builders<OrderDocument>.IndexKeys
.Ascending(o => o.TenantId)
.Ascending(o => o.CustomerId)
.Descending(o => o.CreatedAt); // (1)
await orders.Indexes.CreateOneAsync(
new CreateIndexModel<OrderDocument>(keys),
cancellationToken: ct); // (2)
- (1) Matches tenant and customer equality followed by time ordering. Add a unique tie-breaker to sorting and indexing when pagination requires it.
- (2) Manage index creation as a reviewed deployment change, not per request. Inspect explain executionStats, comparing keysExamined and docsExamined with nReturned.
MongoDB supports compound, unique, multikey array, partial and indexes. Multikey indexes have compound-array and coverage restrictions; do not assume relational equivalence. TTL removal is asynchronous, not an exact expiry deadline, so query or authorization logic must still check validity. Unique indexes on sharded collections have shard-key restrictions. Every index adds storage, memory and write costs.
#Redis data structures beyond caching
Some workloads need membership, ranking or an event log rather than under a key. Redis provides operations that avoid application-level read-modify-write.
| Structure | Example | Important detail |
|---|---|---|
| String | Counter, or cached value | INCR is atomic; and eviction policies matter |
| Hash | Cart fields | Update a field without serializing a whole object |
| Set | Unique users interested in a product | Membership and intersections |
| Sorted set | Products ranked by popularity | Unique members with scores; not a decimal money ledger |
| List | Simple queue | A pop alone is not a processing acknowledgement protocol |
| Stream | Order events with consumer groups | Pending entries, acknowledgements, replay and retention need management |
| Bitmap / HyperLogLog / Geo | Daily activity, approximate unique counts and nearby stores | Different semantics, accuracy and costs |
HSET cart:{customer-9} product-3 2
SADD product:3:interested customer-9
ZINCRBY products:popular 1 product-3
XADD orders:events * orderId order-42 status paid
XGROUP CREATE orders:events fulfilment 0 MKSTREAM
XREADGROUP GROUP fulfilment worker-1 COUNT 10 STREAMS orders:events >
# After durable processing: XACK orders:events fulfilment <message-id>
These are illustrative redis-cli commands; create the group once and handle an existing group. Stream consumers must recover abandoned pending messages and process idempotently after crashes. Pub/Sub differs because disconnected subscribers have no stored backlog. Lua or can group server operations atomically under cluster key constraints; Redis does not provide relational rollback for every runtime command error. Persistence, and failover configuration determine durability.
#Using MongoDB and Cosmos DB from .NET
Use native SDKs for explicit control over database operations, or an provider when its abstraction and translation limits fit. Switching providers does not make a document database relational.
// MongoDB.Driver; register and reuse MongoClient for its connection pools.
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Driver;
var client = new MongoClient(mongoConnectionString);
var orders = client.GetDatabase("store")
.GetCollection<OrderDocument>("orders");
var filter = Builders<OrderDocument>.Filter.And(
Builders<OrderDocument>.Filter.Eq(o => o.TenantId, tenantId),
Builders<OrderDocument>.Filter.Eq(o => o.Id, orderId)); // (1)
var order = await orders.Find(filter).FirstOrDefaultAsync(ct);
public sealed class OrderDocument
{
[BsonId] public string Id { get; set; } = "";
public string TenantId { get; set; } = "";
public string CustomerId { get; set; } = "";
public DateTime CreatedAt { get; set; }
}
- (1) Obtain tenant scope from trusted authorization context and combine it with order identity. BsonId maps Id to _id. Typed filters avoid assembling query from untrusted strings.
// Microsoft.Azure.Cosmos; reuse CosmosClient. Existing /tenantId container assumed.
using Microsoft.Azure.Cosmos;
var cosmos = new CosmosClient(cosmosConnectionString);
var container = cosmos.GetContainer("store", "orders");
try
{
var response = await container.ReadItemAsync<CosmosOrder>(
id: orderId, partitionKey: new PartitionKey(tenantId),
cancellationToken: ct); // (2)
Console.WriteLine(response.RequestCharge);
}
catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
{
Console.WriteLine("Order not found in the authorized partition");
}
public sealed record CosmosOrder(string id, string tenantId, string status);
- (2) A point read needs id and partition key; identity is unique within the logical partition. Monitor RU and diagnostics. Handle 429 through bounded retry policies, not infinite loops. Use ETag with IfMatchEtag for optimistic updates when required.
| Route | Boundaries to review |
|---|---|
| Microsoft.EntityFrameworkCore.Cosmos | Container and partition mapping and translation; not relational migrations or arbitrary joins |
| MongoDB.EntityFrameworkCore | Official MongoDB provider; verify version compatibility and unsupported EF features |
| Native SDKs | Explicit sessions, batches and diagnostics; mapping and abstraction remain application responsibilities |
Use secret storage or managed identity where supported rather than source credentials. These snippets assume provisioned databases and collections and 10 with compatible packages. Reuse clients instead of creating them per request.
#Polyglot persistence and SQL versus NoSQL decisions
Different stores can improve particular workloads while multiplying backups, monitoring, skills and consistency work. Polyglot persistence is a cost decision, not a goal itself.
| Need | Reasonable starting point | Key question |
|---|---|---|
| Related orders and payments with constraints | Often a relational database | Which and reporting boundaries matter? |
| Bounded documents and known access patterns | Document store or PostgreSQL | Embed or reference, and who maintains copies? |
| Key lookups, and atomic structures | Redis or DynamoDB based on durability and operations | Is the data authoritative or derived? |
| Text relevance and faceting | Search engine or relational search, depending on scale | How much indexing lag is acceptable? |
| Repeated relationship traversal | Graph engine or recursive relational queries | Do depth and size justify another store? |
| Semantic similarity | pgvector or another vector-capable engine | What recall, filtering, and access controls are needed? |
-- PostgreSQL: stable relational facts plus variable product attributes.
CREATE TABLE products (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
name text NOT NULL,
price numeric(18,2) NOT NULL CHECK (price >= 0),
attributes jsonb NOT NULL DEFAULT '{}'::jsonb -- (1)
);
CREATE INDEX ix_products_attributes ON products USING gin (attributes);
SELECT id, name FROM products
WHERE attributes @> '{"color":"blue"}'::jsonb; -- (2)
- (1) JSONB supports sparse attributes while retaining relational keys, constraints and transactions.
- (2) A GIN index can support containment. Equality or range access on a particular field may favor a targeted B-tree expression index.
JSONB does not automatically shard data, and large updates and indexing still cost work. When owns truth and search is derived, use an or , consumers and reconciliation rather than naïve dual writes. Support index rebuilds, deletes and versions. Search results must honor authorization even if the index is stale.
References: Cosmos DB consistency, MongoDB .NET transactions, DynamoDB transactions, Redis data types, PostgreSQL JSONB, and the PACELC paper. Examples are independent excerpts. The transaction example assumes collections and models with the fields used; verify package versions against provider compatibility.
Interview questions
No results
Check your reasoning
Why does this choice fit? When would it fail? What changes under higher load or a dependency failure?
11.1Why would you choose a NoSQL database?Junior
I choose a database when its data model and operational guarantees fit a concrete access pattern better than a relational design. Examples include bounded document aggregates, predictable key-based access, graph traversal or search relevance. I compare consistency, boundaries, query flexibility and operational cost. I do not assume NoSQL means no , automatic scalability or no transactions. If relational constraints and changing reports dominate, a relational database may remain the simpler choice.
11.2What are the main NoSQL families?Junior
I distinguish document stores for aggregates, key-value stores for known-key access, wide-column stores for partition-oriented workloads and graph databases for traversals. Search engines specialize in relevance, time-series engines in timestamped measurements, and vector capabilities in similarity search. The boundaries overlap: DynamoDB supports document values, and PostgreSQL can provide vector search through pgvector. I use the categories to understand access patterns, not as rigid labels that determine every guarantee of a product.
11.3Does a document database have no schema?Junior
I consider a document database -flexible rather than schema-free. Documents still have field names, types and assumptions that application readers depend on. I define validation rules for important , version evolving document shapes and support older documents during rollout. I also choose stable money and date representations. Without that discipline, flexibility simply moves schema errors from deployment time to runtime and makes migrations and analytics harder to reason about.
11.4When should you embed data instead of referencing it?Junior
I embed data when it is bounded, owned by the parent and commonly read or changed with it, such as order lines. I reference independently changing entities such as customers and products, and avoid unbounded arrays such as every order inside one customer. I may retain purchase-time snapshots separately from current records. The decision considers document size, write contention and consistency, not just reducing one join or one network call.
11.5How do sharding and replication differ?Junior
I use to distribute different portions of a dataset across nodes, increasing capacity and spreading workload when the key is suitable. keeps multiple copies of the same portion for resilience and read locality. A sharded cluster can replicate every shard. Neither removes design work: sharding needs routing and balance, while replication needs consistency and failover policies. I would not expect adding replicas alone to solve a single hot write partition.
11.6What is eventual consistency?Junior
I understand as convergence when writes stop and updates can propagate. It does not by itself guarantee a maximum delay or that an immediate read sees my write. I use it for workloads that tolerate stale results, such as a derived product search index, and define how that staleness appears to users. For decisions like reserving the last item, I need a stronger operation or an authoritative conditional write.
11.7How would you model orders and customers in a document database?Mid
I start from queries: point-reading an order, listing a customer's history and changing order state. I store each order separately with bounded lines and purchase-time snapshots, while CustomerId references the current customer. I do not append unlimited orders to one customer document. I then choose partitioning and indexes for those queries and define how copied current facts would be synchronized. Historical prices and shipping details should not change when the catalog or customer record changes.
11.8What makes a good partition key?Mid
I look for enough distinct values, balanced data and traffic, and routing that matches the main queries. I evaluate the busiest tenant or customer, not just average size, and consider and uniqueness scope. A high- key can still be hot if one value receives most requests. Bucketing may spread writes but makes reads and ordering harder. I also review key-change and resharding costs because a convenient initial key can become expensive to replace.
11.9How would you diagnose a hot partition?Mid
I inspect per-partition , and throttling, then identify which logical keys dominate traffic or storage. I check whether range growth concentrates writes or one tenant overwhelms an otherwise balanced design. Possible remedies include a different compound key, bounded time buckets or hash buckets, but each changes routing and read fan-out. I test the largest cases and plan data migration. Adding replicas may improve some reads without fixing a single overloaded write key.
11.10What are leader-follower, multi-leader and leaderless replication?Mid
I distinguish a leader accepting writes and replicating to followers from multiple leaders accepting writes in different locations. The latter needs explicit conflict handling. Leaderless systems coordinate reads and writes across replicas with configurable acknowledgements, versions and repair mechanisms. Each model has trade-offs around , stale reads, failover and concurrent updates. I check the actual implementation and settings rather than assuming a model name proves durability or strong consistency.
11.11What does R + W > N mean in quorum replication?Mid
I use N for replica count, W for required write acknowledgements and R for required read responses. If R plus W exceeds N over the same fixed replica set, successful read and write quorums intersect. That helps a read encounter an acknowledged write, but does not alone guarantee linearizability. Correct version selection, concurrent and failed writes, membership changes and sloppy- behavior still matter. I rely on the database's documented protocol rather than treating the inequality as a complete proof.
11.12How does session consistency improve user experience in Cosmos DB?Mid
I use session consistency when a user should see their own changes without requiring every user to observe the globally latest value. Session help maintain read-your-writes and monotonic reads within the relevant session scope. Reusing a client helps manage tokens, but a user moving between application instances may require explicit propagation. I still distinguish this from an atomic business and verify the and partition scope of the guarantees I depend on.
11.13How do you index a MongoDB order-history query?Mid
I begin with the query shape, for example tenant and customer equality followed by creation-time ordering. A compound index in that order is a candidate, with a unique tie-breaker if pagination needs deterministic order. I inspect explain statistics to compare examined keys and documents with returned rows, and verify that sorting is supported. I account for index storage and write cost and review array, partial and unique-index restrictions rather than indexing every field.
11.14What can Redis do beyond caching?Mid
I use Redis structures for specific operations: hashes for cart fields, sets for membership, sorted sets for popularity rankings and atomic counters for usage. Streams support retained events and consumer groups, while lists support simpler queues. I distinguish Streams from Pub/Sub, which does not retain messages for disconnected consumers. Durability, eviction, and recovery policies still need design. An atomic command also does not automatically make an entire business workflow exactly-once.
11.15How do you access MongoDB and Cosmos DB efficiently from .NET?Mid
I reuse MongoClient and CosmosClient so their connection management and session behavior are effective. For MongoDB I use typed filters and appropriate indexes. For Cosmos point reads I supply both id and partition key and monitor request charges and diagnostics. I handle not-found and throttling deliberately, propagate cancellation and protect credentials. providers are available, but I verify their translation and feature limitations instead of expecting relational joins and migrations from every provider.
11.16Explain CAP precisely and how PACELC extends the discussion.Senior
I explain as a limitation during a network partition: a system cannot guarantee both linearizable behavior and completion of every request to every non-failing node. It is not a blanket choose-two slogan, and consistency here differs from validity. adds the healthy-network trade-off between and consistency, because coordination still takes time without a failure. I discuss the guarantee for a particular operation and configuration rather than labeling an entire product permanently.
11.17Can NoSQL databases provide ACID transactions?Senior
Yes. I check the supported scope rather than assuming the data model excludes . MongoDB supports multi-document transactions on suitable deployments, DynamoDB offers TransactWriteItems, and Cosmos for has transactional batches within one logical partition and container. Their limits, , retry behavior and costs differ. I model aggregates to keep important local where possible and use conditional writes when sufficient, rather than assuming every distributed operation can join one unlimited transaction.
11.18What can go wrong when a transaction callback is retried?Senior
I assume a retryable callback may execute more than once. Sending email or charging a remote provider inside it can duplicate side effects even if the database changes roll back. I keep the callback limited to database work, pass its session to every operation and use stable identifiers and an where needed. I do not swallow failures or run unsupported parallel operations. I also plan for ambiguous commit outcomes and reconciliation instead of treating a timeout as proof of failure.
11.19How would you keep SQL and a search index consistent?Senior
I make one store authoritative and treat the search index as rebuildable derived data. I publish changes through an or rather than independently writing both stores in a request. Consumers handle duplicates, ordering and document versions, including deletions. I monitor lag, support replay and reconcile drift. The product defines acceptable search staleness, and sensitive access checks do not trust a stale index alone. A rebuild procedure is part of the design, not an emergency improvisation.
11.20When is PostgreSQL JSONB enough, and when would you add another store?Senior
I consider when variable attributes belong alongside relational facts and I still need joins, constraints and familiar . Targeted expression indexes or GIN may support the access patterns without another service. I add a specialized store only when measured search, graph, partitioning or requirements justify its operational and consistency costs. JSONB is not automatic , but document flexibility alone is also not a sufficient reason to operate multiple databases.
Test yourself
Quiz answers and completed-topic marks are saved in this browser; they do not sync across devices.
Which data is usually best embedded inside an order?
A partition key has many values but one receives most writes. What follows?
What does R + W > N guarantee under fixed replica-set assumptions?
CAP consistency refers to...
Which Cosmos DB level is commonly chosen for read-your-writes within a session?
Cosmos DB for NoSQL transactional batches normally require...
MongoDB TTL indexing means an expired record...
Which Redis facility retains entries and supports consumer groups?
What does a Cosmos DB point read need besides an item id?
Which design avoids naïve SQL-plus-search dual writes?