» Webform submission data `name_property` index causes inefficient MariaDB join plans
Summary
Webform 6.3 adds the following index to `webform_submission_data`:
```sql
INDEX name_property (name, property)
```
On MariaDB, this index can cause Views queries that join Webform submission fields to select inefficient execution plans.
Environment
- Drupal with Webform 6.3
- MariaDB
- Views query joining multiple fields from `webform_submission_data`
Problem
The appointment View initially used inefficient plans when `name_property` existed:
- Webform field joins did not consistently use `PRIMARY`.
- Some joins used less suitable indexes.
- Join buffers were used.
- Page load time was significantly slower.
After removing the index and running:
```sql
ALTER TABLE webform_submission_data
DROP INDEX name_property;
ANALYZE TABLE webform_submission_data;
```
the execution plan changed:
```text
type=eq_ref
key=PRIMARY
rows=1
```
All Webform field joins then used the primary key:
The `(name, property)` index changes MariaDB’s optimizer choice and results in inefficient join plans for Views that join multiple Webform fields.
Suggested resolution
Please investigate whether the `name_property` index should:
1. Be removed from the Webform submission-data schema;
2. Be replaced with an index whose leading column is `sid`; or
3. Be retained but prevented from being selected for this join pattern through a schema/query adjustment.
A possible improvement would be to add a regression test using MariaDB that verifies Webform field joins continue to use the primary key and do not introduce join buffers.
Webform 6.3 adds the following index to `webform_submission_data`:
```sql
INDEX name_property (name, property)
```
On MariaDB, this index can cause Views queries that join Webform submission fields to select inefficient execution plans.
Environment
- Drupal with Webform 6.3
- MariaDB
- Views query joining multiple fields from `webform_submission_data`
Problem
The appointment View initially used inefficient plans when `name_property` existed:
- Webform field joins did not consistently use `PRIMARY`.
- Some joins used less suitable indexes.
- Join buffers were used.
- Page load time was significantly slower.
After removing the index and running:
```sql
ALTER TABLE webform_submission_data
DROP INDEX name_property;
ANALYZE TABLE webform_submission_data;
```
the execution plan changed:
```text
type=eq_ref
key=PRIMARY
rows=1
```
All Webform field joins then used the primary key:
The `(name, property)` index changes MariaDB’s optimizer choice and results in inefficient join plans for Views that join multiple Webform fields.
Suggested resolution
Please investigate whether the `name_property` index should:
1. Be removed from the Webform submission-data schema;
2. Be replaced with an index whose leading column is `sid`; or
3. Be retained but prevented from being selected for this join pattern through a schema/query adjustment.
A possible improvement would be to add a regression test using MariaDB that verifies Webform field joins continue to use the primary key and do not introduce join buffers.
Compacted conversationI'll explain the technical root cause of why the `name_property` index creates the load time issue. Let me look at the detailed analysis first:
Why the `name_property` Index Causes the Load Time Issue
Here's the technical explanation:
**The Core Problem: Optimizer Trap**
The `name_property (name, property)` index creates an "optimizer trap" where MariaDB chooses a suboptimal execution plan even though a better option (the PRIMARY KEY) is available.
**Table Structure**
```
webform_submission_data:
├── PRIMARY KEY (sid, name, property, delta) ← Optimal for Views joins
├── INDEX name_property (name, property) ← Added in Webform 6.3 (problematic)
├── Other indexes for data export/search
```
### **Typical Views Query Pattern**
When Views retrieves submission data from multiple webform fields:
```sql
SELECT ws.sid, ws.created
FROM webform_submission ws
JOIN webform_submission_data wsd1 ON ws.sid = wsd1.sid AND wsd1.name = 'owner_firstname'
JOIN webform_submission_data wsd2 ON ws.sid = wsd2.sid AND wsd2.name = 'owner_lastname'
WHERE ws.webform_id = 'appointment'
```
**Why the Optimizer Chooses the Wrong Index**
**The Join Condition**: `ws.sid = wsd.sid AND wsd.name = 'field_name'`
1. **What should happen** (uses PRIMARY KEY):
```
Join Key: (sid, name)
- Lookup by sid FIRST (via PRIMARY KEY)
- Then filter by name within that result set
- Rows examined: 1-10 per join
- Join Buffer: NOT NEEDED
- Type: eq_ref (exact match)
```
2. **What actually happens** (uses name_property):
```
Join Key: (name) only
- Lookup by name FIRST (via name_property index)
- Then seek by sid (NOT in index, not optimized)
- Rows examined: 1,000-2,000 per join
- Join Buffer: REQUIRED (memory overhead)
- Type: ref (range/match)
```
**Why the Optimizer Thinks name_property is Better**
MariaDB's cost-based optimizer considers:
1. **Index selectivity**:
- `name_property` starts with `name` column
- If there are ~250 webform fields, filtering by a specific field name seems selective
- "I'll find rows where name='owner_firstname' very quickly"
2. **Cost estimation**:
- Optimizer estimates: "name='owner_firstname' → ~4,000 rows"
- Then estimates: "sid matching within those 4,000 rows"
- Cost looks lower than PRIMARY KEY scan
3. **Missing join context**:
- Optimizer doesn't fully account for the `sid=?` part of the join
- Doesn't realize PRIMARY KEY `(sid, name, property, delta)` can satisfy both conditions together
When the optimizer can't use the index for a join condition, it stores rows from the first table in memory (join buffer):
```
Without Join Buffer (eq_ref):
├─ For each row from first table
│ └─ Direct pointer lookup (1 disk seek)
With Join Buffer (ref):
├─ Buffer first table rows in memory (50-100KB)
├─ Scan buffered rows for each candidate from second table
├─ Multiple disk seeks per row
└─ Higher CPU cache misses
```
This is why the performance is **35-50% slower**.
### **The Fix: Remove the Trap**
```sql
ALTER TABLE webform_submission_data DROP INDEX name_property;
```
**Result**:
- No optimizer confusion
- PRIMARY KEY is now the only choice
- Direct `(sid, name)` matching
- No join buffers
- 35-50% faster queries
**Why Webform Added It in the First Place**
Webform 6.3 likely added this index for queries like:
```sql
-- Search data export by field name
SELECT * FROM webform_submission_data
WHERE name = 'email' AND property = 'value';
-- Get all values for a specific field
SELECT * FROM webform_submission_data
WHERE name = 'owner_firstname'
ORDER BY value;
```
But for Views joining on submission ID + field name, it's counterproductive.
---
**Key Insight: Index Ordering Matters**
The PRIMARY KEY `(sid, name, property, delta)` works beautifully for:
- **Views joins**: `sid = ? AND name = ?` ✅
- **Data export**: Scan by sid, then iterate fields ✅
The `name_property` index `(name, property)` is optimized for:
- **Field searches**: `name = ?` (but Views doesn't use this pattern)
- **Data extraction**: `name = ? AND property = ?` (rare in Views)
For a Views-based application, the PRIMARY KEY is sufficient and optimal.
That's why removing the index provides 35-50% improvement: it eliminates the optimizer trap and forces the use of the already-perfect PRIMARY KEY.
Comments
Comment #2
cilefen commentedComment #4
pemson18Summary
Webform 6.3 adds the following index to `webform_submission_data`:
```sql
INDEX name_property (name, property)
```
On MariaDB, this index can cause Views queries that join Webform submission fields to select inefficient execution plans.
Environment
- Drupal with Webform 6.3
- MariaDB
- Views query joining multiple fields from `webform_submission_data`
Problem
The appointment View initially used inefficient plans when `name_property` existed:
- Webform field joins did not consistently use `PRIMARY`.
- Some joins used less suitable indexes.
- Join buffers were used.
- Page load time was significantly slower.
After removing the index and running:
```sql
ALTER TABLE webform_submission_data
DROP INDEX name_property;
ANALYZE TABLE webform_submission_data;
```
the execution plan changed:
```text
type=eq_ref
key=PRIMARY
rows=1
```
All Webform field joins then used the primary key:
```sql
PRIMARY KEY (sid, name, property, delta)
```
The appointment View timing improved to approximately:
```text
0.022–0.033 seconds
```
The query portion was consistently approximately:
```text
0.017 seconds
```
## Expected behavior
The additional index should not cause MariaDB to select a slower plan for joins using:
```sql
sid, name, property, delta
```
These joins are optimally supported by the existing primary key:
```sql
PRIMARY KEY (sid, name, property, delta)
```
## Actual behavior
The `(name, property)` index changes MariaDB’s optimizer choice and results in inefficient join plans for Views that join multiple Webform fields.
Suggested resolution
Please investigate whether the `name_property` index should:
1. Be removed from the Webform submission-data schema;
2. Be replaced with an index whose leading column is `sid`; or
3. Be retained but prevented from being selected for this join pattern through a schema/query adjustment.
A possible improvement would be to add a regression test using MariaDB that verifies Webform field joins continue to use the primary key and do not introduce join buffers.
Comment #5
pemson18Summary
Webform 6.3 adds the following index to `webform_submission_data`:
```sql
INDEX name_property (name, property)
```
On MariaDB, this index can cause Views queries that join Webform submission fields to select inefficient execution plans.
Environment
- Drupal with Webform 6.3
- MariaDB
- Views query joining multiple fields from `webform_submission_data`
Problem
The appointment View initially used inefficient plans when `name_property` existed:
- Webform field joins did not consistently use `PRIMARY`.
- Some joins used less suitable indexes.
- Join buffers were used.
- Page load time was significantly slower.
After removing the index and running:
```sql
ALTER TABLE webform_submission_data
DROP INDEX name_property;
ANALYZE TABLE webform_submission_data;
```
the execution plan changed:
```text
type=eq_ref
key=PRIMARY
rows=1
```
All Webform field joins then used the primary key:
```sql
PRIMARY KEY (sid, name, property, delta)
```
The appointment View timing improved to approximately:
```text
0.022–0.033 seconds
```
The query portion was consistently approximately:
```text
0.017 seconds
```
## Expected behavior
The additional index should not cause MariaDB to select a slower plan for joins using:
```sql
sid, name, property, delta
```
These joins are optimally supported by the existing primary key:
```sql
PRIMARY KEY (sid, name, property, delta)
```
## Actual behavior
The `(name, property)` index changes MariaDB’s optimizer choice and results in inefficient join plans for Views that join multiple Webform fields.
Suggested resolution
Please investigate whether the `name_property` index should:
1. Be removed from the Webform submission-data schema;
2. Be replaced with an index whose leading column is `sid`; or
3. Be retained but prevented from being selected for this join pattern through a schema/query adjustment.
A possible improvement would be to add a regression test using MariaDB that verifies Webform field joins continue to use the primary key and do not introduce join buffers.
Comment #6
cilefen commentedComment #7
pemson18Compacted conversationI'll explain the technical root cause of why the `name_property` index creates the load time issue. Let me look at the detailed analysis first:
Why the `name_property` Index Causes the Load Time Issue
Here's the technical explanation:
**The Core Problem: Optimizer Trap**
The `name_property (name, property)` index creates an "optimizer trap" where MariaDB chooses a suboptimal execution plan even though a better option (the PRIMARY KEY) is available.
**Table Structure**
```
webform_submission_data:
├── PRIMARY KEY (sid, name, property, delta) ← Optimal for Views joins
├── INDEX name_property (name, property) ← Added in Webform 6.3 (problematic)
├── Other indexes for data export/search
```
### **Typical Views Query Pattern**
When Views retrieves submission data from multiple webform fields:
```sql
SELECT ws.sid, ws.created
FROM webform_submission ws
JOIN webform_submission_data wsd1 ON ws.sid = wsd1.sid AND wsd1.name = 'owner_firstname'
JOIN webform_submission_data wsd2 ON ws.sid = wsd2.sid AND wsd2.name = 'owner_lastname'
WHERE ws.webform_id = 'appointment'
```
**Why the Optimizer Chooses the Wrong Index**
**The Join Condition**: `ws.sid = wsd.sid AND wsd.name = 'field_name'`
1. **What should happen** (uses PRIMARY KEY):
```
Join Key: (sid, name)
- Lookup by sid FIRST (via PRIMARY KEY)
- Then filter by name within that result set
- Rows examined: 1-10 per join
- Join Buffer: NOT NEEDED
- Type: eq_ref (exact match)
```
2. **What actually happens** (uses name_property):
```
Join Key: (name) only
- Lookup by name FIRST (via name_property index)
- Then seek by sid (NOT in index, not optimized)
- Rows examined: 1,000-2,000 per join
- Join Buffer: REQUIRED (memory overhead)
- Type: ref (range/match)
```
**Why the Optimizer Thinks name_property is Better**
MariaDB's cost-based optimizer considers:
1. **Index selectivity**:
- `name_property` starts with `name` column
- If there are ~250 webform fields, filtering by a specific field name seems selective
- "I'll find rows where name='owner_firstname' very quickly"
2. **Cost estimation**:
- Optimizer estimates: "name='owner_firstname' → ~4,000 rows"
- Then estimates: "sid matching within those 4,000 rows"
- Cost looks lower than PRIMARY KEY scan
3. **Missing join context**:
- Optimizer doesn't fully account for the `sid=?` part of the join
- Doesn't realize PRIMARY KEY `(sid, name, property, delta)` can satisfy both conditions together
**The Performance Consequence**
**With name_property index (WRONG)**:
```
Query: JOIN webform_submission_data wsd1 ... wsd2 ...
├── First join (wsd1):
│ ├── Uses name_property index
│ ├── Rows examined: 1,000-2,000
│ ├── Join Buffer: 50KB
│ └── Time: 15-20ms
├── Second join (wsd2):
│ ├── Uses name_property index
│ ├── Rows examined: 1,000-2,000
│ ├── Join Buffer: 50KB
│ └── Time: 15-20ms
└── Total: 35-45ms ⚠️ SLOW
```
**With PRIMARY KEY only (CORRECT)**:
```
Query: JOIN webform_submission_data wsd1 ... wsd2 ...
├── First join (wsd1):
│ ├── Uses PRIMARY KEY
│ ├── Rows examined: 1-2
│ ├── Join Buffer: NONE
│ └── Time: 3-5ms
├── Second join (wsd2):
│ ├── Uses PRIMARY KEY
│ ├── Rows examined: 1-2
│ ├── Join Buffer: NONE
│ └── Time: 3-5ms
└── Total: 8-15ms ✅ FAST (44-50% improvement)
```
**Why Join Buffers Make It Worse**
When the optimizer can't use the index for a join condition, it stores rows from the first table in memory (join buffer):
```
Without Join Buffer (eq_ref):
├─ For each row from first table
│ └─ Direct pointer lookup (1 disk seek)
With Join Buffer (ref):
├─ Buffer first table rows in memory (50-100KB)
├─ Scan buffered rows for each candidate from second table
├─ Multiple disk seeks per row
└─ Higher CPU cache misses
```
This is why the performance is **35-50% slower**.
### **The Fix: Remove the Trap**
```sql
ALTER TABLE webform_submission_data DROP INDEX name_property;
```
**Result**:
- No optimizer confusion
- PRIMARY KEY is now the only choice
- Direct `(sid, name)` matching
- No join buffers
- 35-50% faster queries
**Why Webform Added It in the First Place**
Webform 6.3 likely added this index for queries like:
```sql
-- Search data export by field name
SELECT * FROM webform_submission_data
WHERE name = 'email' AND property = 'value';
-- Get all values for a specific field
SELECT * FROM webform_submission_data
WHERE name = 'owner_firstname'
ORDER BY value;
```
But for Views joining on submission ID + field name, it's counterproductive.
---
**Key Insight: Index Ordering Matters**
The PRIMARY KEY `(sid, name, property, delta)` works beautifully for:
- **Views joins**: `sid = ? AND name = ?` ✅
- **Data export**: Scan by sid, then iterate fields ✅
The `name_property` index `(name, property)` is optimized for:
- **Field searches**: `name = ?` (but Views doesn't use this pattern)
- **Data extraction**: `name = ? AND property = ?` (rare in Views)
For a Views-based application, the PRIMARY KEY is sufficient and optimal.
That's why removing the index provides 35-50% improvement: it eliminates the optimizer trap and forces the use of the already-perfect PRIMARY KEY.