Excellent question! When multiple transactions access the same data concurrently, various data anomalies can occur — especially if isolation levels are low.
These problems can cause inconsistent, incorrect, or even lost data if not handled properly.
🔍 Common Problems with Concurrent Transactions:
1. 🧼 Dirty Read
One transaction reads uncommitted changes made by another.
Example:
T1 updates balance = 500 → 600 but hasn’t committed.
T2 reads balance = 600.
T1 rolls back → T2 used invalid data.
🔒 Prevented by: READ COMMITTED and higher.
2. 🔁 Non-Repeatable Read
A row is read twice, and the value changes between reads within the same transaction.
Example:
T1 reads user email = alice@mail.com.
T2 updates it to alice@new.com and commits.
T1 reads again: value changed.
🔒 Prevented by: REPEATABLE READ and SERIALIZABLE.
3. 👻 Phantom Read
A query returns different sets of rows when run twice in the same transaction due to new rows being inserted.
Example:
T1: SELECT * FROM Orders WHERE total > 100;
T2: inserts a new matching order and commits.
T1 runs the same query again — now sees a new row.
🔒 Prevented by: SERIALIZABLE.
4. ❌ Lost Update
Two transactions read the same row, modify it, and write back, overwriting each other’s changes.
Example:
T1 reads balance = 500, adds 100 → sets to 600
T2 also reads 500, adds 200 → sets to 700
Final result = 700 ❌ (T1’s change is lost)
🔒 Prevented by: proper locking, SERIALIZABLE, or optimistic concurrency control.
🧠 Summary Table:
Problem
Description
Prevented by
Dirty Read
Reading uncommitted data
READ COMMITTED or higher
Non-Repeatable Read
Same row read twice gives different data
REPEATABLE READ or higher
Phantom Read
Re-executed query returns new rows
SERIALIZABLE
Lost Update
Concurrent writes overwrite each other
Locks, optimistic concurrency
Posted inБез рубрики|Comments Off on Database.What problems can arise with concurrent access using transactions?
Transaction isolation levels define how isolated a transaction is from others — i.e., how much one transaction can “see” the uncommitted changes of another.
They are standardized by SQL ANSI and help balance data consistency vs performance.
🔒 The 4 Standard Isolation Levels (from lowest to highest):
Isolation Level
Prevents
Allows
Performance
Consistency
READ UNCOMMITTED
✖ Dirty reads
✓ All anomalies
🔥 Fastest
😵 Weakest
READ COMMITTED
✔ Dirty reads
✖ Non-repeatable, phantom reads
⚡ Fast
😐 Fair
REPEATABLE READ
✔ Dirty + non-repeatable reads
✖ Phantom reads
⏳ Moderate
😊 Strong
SERIALIZABLE
✔ All anomalies
✖ Everything
🐢 Slowest
💎 Strongest
🧪 What Does Each Level Do?
1. READ UNCOMMITTED
Transactions can see uncommitted changes of others.
Prone to dirty reads (reading data that may be rolled back).
Rarely used due to danger of corrupt logic.
2. READ COMMITTED (default in many DBs)
Can only read committed data.
Prevents dirty reads, but still allows:
❌ Non-repeatable reads (same query returns different results)
❌ Phantom reads (rows appear/disappear in repeated queries)
3. REPEATABLE READ
Prevents dirty reads and non-repeatable reads.
Ensures same query in same transaction always sees same rows.
Still allows phantom reads (new rows may show up if using SELECT WHERE)
4. SERIALIZABLE
Strictest level: transactions are executed as if they were serial (one at a time).
Prevents:
Dirty reads
Non-repeatable reads
Phantom reads
Ensures full isolation but with lower concurrency and higher locking overhead.
Usually, no, it does not make sense to index columns with a small number of distinct values (i.e., low cardinality), unless there’s a very specific reason.
📉 Why Not?
Columns like:
gender = 'M' or 'F'
status = 'active' or 'inactive'
is_deleted = true or false
Have very few possible values, so:
Each index entry matches many rows
The database will likely do a full table scan anyway, because the index isn’t selective
Using the index can be slower than just scanning the table
🔍 When Might It Still Make Sense?
✅ 1. In combination with other columns (composite index)
CREATE INDEX idx_status_created ON Users(status, created_at);
Useful if you often query:
SELECT * FROM Users
WHERE status = 'active' AND created_at > '2024-01-01';
Here, status helps narrow the data before applying the range on created_at.
✅ 2. In large, filtered queries or partitions
If:
The table is huge, and
The low-cardinality column is highly skewed (e.g., 90% 'active', 10% 'inactive'), and
You often query the rare value:
SELECT * FROM Users WHERE status = 'inactive';
Then an index might help — but it depends on the query planner and row distribution.
✅ 3. Bitmap Indexes (in data warehouses)
In OLAP databases (e.g., Oracle, Redshift), low-cardinality columns are perfect for bitmap indexes, which compress well and are efficient for complex filtering.
🧠 Rule of Thumb:
Cardinality
Should You Index?
🔴 Very low (e.g., true/false)
❌ No — often worse performance
🟡 Medium
⚠️ Depends on query patterns and size
🟢 High (e.g., email, ID)
✅ Yes — ideal for indexing
Posted inБез рубрики|Comments Off on Database.Does it make sense to index data that has a small number of possible values?