mysql+proxysql: 5-MOAD scan; mysql-0005 CWE-407 row0sel template_col O(T*C) per row 31.5x, proxysql-0002 CWE-407 FTS indexed_cols O(R*C*I) 7.8x
This commit is contained in:
parent
decacb5dbd
commit
7822bb0e85
6 changed files with 437 additions and 0 deletions
|
|
@ -9,6 +9,7 @@ import java.util.*;
|
|||
* mysql-0002: has_global_grant fallback — O(P) multimap equal_range+find vs O(1) map lookup
|
||||
* mysql-0003: setup_fields() iterator recovery — O(F²) std::find vs O(F) index loop
|
||||
* mysql-0004: dict_index_find_and_set_cols() col_added — O(F²) std::find vs O(F) unordered_set
|
||||
* mysql-0005: row_sel_store_mysql_rec() template_col — O(T*C) std::find per row vs O(T) hashmap
|
||||
*
|
||||
* No JUnit. Prints N/N PASS.
|
||||
*/
|
||||
|
|
@ -356,8 +357,96 @@ public class MysqlTest {
|
|||
else System.out.println(" PASS mysql-0004");
|
||||
}
|
||||
|
||||
// --- mysql-0005: row_sel_store_mysql_rec template_col O(T*C) std::find per row ---
|
||||
{
|
||||
int T = 50; // template fields (SELECT columns)
|
||||
int C = 50; // secondary index columns
|
||||
int ROWS = 100_000;
|
||||
long[] slowOps = new long[1], fastOps = new long[1];
|
||||
|
||||
Runnable slow = () -> slowOps[0] = templateColSlow(T, C, ROWS);
|
||||
Runnable fast = () -> fastOps[0] = templateColFast(T, C, ROWS);
|
||||
|
||||
slow.run(); fast.run();
|
||||
long t0 = System.nanoTime(); slow.run(); long sMs = (System.nanoTime() - t0) / 1_000_000;
|
||||
long t1 = System.nanoTime(); fast.run(); long fMs = (System.nanoTime() - t1) / 1_000_000;
|
||||
double speedup = fastOps[0] > 0 ? (double) slowOps[0] / fastOps[0] : 0;
|
||||
System.out.printf(" %-60s slow:%4dms (%,d ops) fast:%4dms (%,d ops) speedup:%.1fx%n",
|
||||
"mysql-0005 row0sel template_col O(T*C) vs O(T) hashmap", sMs, slowOps[0], fMs, fastOps[0], speedup);
|
||||
|
||||
total++;
|
||||
// slow: T * C ops per row * ROWS; fast: T ops per row * ROWS; ratio = C = 50
|
||||
boolean pass = slowOps[0] > fastOps[0] * 10L;
|
||||
if (!pass) { System.out.printf(" FAIL mysql-0005: slowOps=%,d fastOps=%,d (expected >10x)%n",
|
||||
slowOps[0], fastOps[0]); failures++; }
|
||||
else System.out.println(" PASS mysql-0005");
|
||||
}
|
||||
|
||||
System.out.println("=".repeat(100));
|
||||
System.out.printf("%d/%d %s%n", total - failures, total, failures == 0 ? "PASS" : "FAIL");
|
||||
if (failures > 0) System.exit(1);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// mysql-0005 — row_sel_store_mysql_rec: O(T*C) vector std::find vs O(T) hashmap
|
||||
//
|
||||
// Models storage/innobase/row/row0sel.cc:row_sel_store_mysql_rec()
|
||||
// template_col: vector<const dict_col_t*> of C secondary index cols
|
||||
// For each of T template fields: std::find(template_col, col) -> O(C)
|
||||
// Total per row: O(T * C)
|
||||
// Fix: unordered_map<col*, sec_field_no> -> O(1) per template field
|
||||
// -----------------------------------------------------------------------
|
||||
static long templateColSlow(int T, int C, int rows) {
|
||||
// Build template_col vector (C pointer-like integers)
|
||||
long[] templateCol = new long[C];
|
||||
for (int i = 0; i < C; i++) templateCol[i] = i + 1000L; // simulate column pointers
|
||||
|
||||
// T template fields - half will be found in templateCol
|
||||
long[] templateFields = new long[T];
|
||||
for (int i = 0; i < T; i++) {
|
||||
templateFields[i] = (i % 2 == 0) ? (i / 2 + 1000L) : (i + 9000L); // half hit, half miss
|
||||
}
|
||||
|
||||
long ops = 0;
|
||||
for (int r = 0; r < rows; r++) {
|
||||
for (int t = 0; t < T; t++) {
|
||||
long col = templateFields[t];
|
||||
// std::find equivalent: O(C) linear scan
|
||||
int foundIdx = -1;
|
||||
for (int c = 0; c < C; c++) {
|
||||
ops++;
|
||||
if (templateCol[c] == col) {
|
||||
foundIdx = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// foundIdx is the sec_field_no (or -1 if not found)
|
||||
long dummy = foundIdx; // prevent dead-code elimination
|
||||
}
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
static long templateColFast(int T, int C, int rows) {
|
||||
// Build template_col_map: HashMap<col, sec_field_no> for O(1) lookup
|
||||
Map<Long, Integer> templateColMap = new HashMap<>(C * 2);
|
||||
for (int i = 0; i < C; i++) templateColMap.put(i + 1000L, i);
|
||||
|
||||
// T template fields
|
||||
long[] templateFields = new long[T];
|
||||
for (int i = 0; i < T; i++) {
|
||||
templateFields[i] = (i % 2 == 0) ? (i / 2 + 1000L) : (i + 9000L);
|
||||
}
|
||||
|
||||
long ops = 0;
|
||||
for (int r = 0; r < rows; r++) {
|
||||
for (int t = 0; t < T; t++) {
|
||||
long col = templateFields[t];
|
||||
ops++; // O(1) hash lookup
|
||||
Integer secFieldNo = templateColMap.get(col);
|
||||
long dummy = (secFieldNo != null) ? secFieldNo : -1;
|
||||
}
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue