Fossil SCM
Add additional markups to show inefficient queries when running in TH3_DEBUG mode.
Commit
251fd001a8c6e7af99500a8ca3ac38ad95577995
Parent
4bbb437f06ec406…
2 files changed
+12
-8
+2
-2
M
src/db.c
+12
-8
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -54,10 +54,11 @@ | ||
| 54 | 54 | */ |
| 55 | 55 | struct Stmt { |
| 56 | 56 | Blob sql; /* The SQL for this statement */ |
| 57 | 57 | sqlite3_stmt *pStmt; /* The results of sqlite3_prepare() */ |
| 58 | 58 | Stmt *pNext, *pPrev; /* List of all unfinalized statements */ |
| 59 | + int nStep; /* Number of sqlite3_step() calls */ | |
| 59 | 60 | }; |
| 60 | 61 | #endif /* INTERFACE */ |
| 61 | 62 | |
| 62 | 63 | /* |
| 63 | 64 | ** Call this routine when a database error occurs. |
| @@ -197,10 +198,11 @@ | ||
| 197 | 198 | zSql = blob_str(&pStmt->sql); |
| 198 | 199 | if( sqlite3_prepare_v2(g.db, zSql, -1, &pStmt->pStmt, 0)!=0 ){ |
| 199 | 200 | db_err("%s\n%s", sqlite3_errmsg(g.db), zSql); |
| 200 | 201 | } |
| 201 | 202 | pStmt->pNext = pStmt->pPrev = 0; |
| 203 | + pStmt->nStep = 0; | |
| 202 | 204 | return 0; |
| 203 | 205 | } |
| 204 | 206 | int db_prepare(Stmt *pStmt, const char *zFormat, ...){ |
| 205 | 207 | int rc; |
| 206 | 208 | va_list ap; |
| @@ -272,44 +274,46 @@ | ||
| 272 | 274 | ** or SQLITE_OK if the statement finishes successfully. |
| 273 | 275 | */ |
| 274 | 276 | int db_step(Stmt *pStmt){ |
| 275 | 277 | int rc; |
| 276 | 278 | rc = sqlite3_step(pStmt->pStmt); |
| 279 | + pStmt->nStep++; | |
| 277 | 280 | return rc; |
| 278 | 281 | } |
| 279 | 282 | |
| 280 | 283 | /* |
| 281 | 284 | ** Print warnings if a query is inefficient. |
| 282 | 285 | */ |
| 283 | -static void db_stats(sqlite3_stmt *pStmt){ | |
| 286 | +static void db_stats(Stmt *pStmt){ | |
| 284 | 287 | #ifdef FOSSIL_DEBUG |
| 285 | 288 | int c1, c2; |
| 286 | - const char *zSql = sqlite3_sql(pStmt); | |
| 289 | + const char *zSql = sqlite3_sql(pStmt->pStmt); | |
| 287 | 290 | if( zSql==0 ) return; |
| 288 | - c1 = sqlite3_stmt_status(pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, 1); | |
| 289 | - c2 = sqlite3_stmt_status(pStmt, SQLITE_STMTSTATUS_SORT, 1); | |
| 290 | - if( c1>5 && strstr(zSql,"/*scan*/")==0 ){ | |
| 291 | - fossil_warning("%d scan steps in [%s]", c1, zSql); | |
| 291 | + c1 = sqlite3_stmt_status(pStmt->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, 1); | |
| 292 | + c2 = sqlite3_stmt_status(pStmt->pStmt, SQLITE_STMTSTATUS_SORT, 1); | |
| 293 | + if( c1>pStmt->nStep*4 && strstr(zSql,"/*scan*/")==0 ){ | |
| 294 | + fossil_warning("%d scan steps for %d rows in [%s]", c1, pStmt->nStep, zSql); | |
| 292 | 295 | }else if( c2 && strstr(zSql,"/*sort*/")==0 && strstr(zSql,"/*scan*/")==0 ){ |
| 293 | 296 | fossil_warning("sort w/o index in [%s]", zSql); |
| 294 | 297 | } |
| 298 | + pStmt->nStep = 0; | |
| 295 | 299 | #endif |
| 296 | 300 | } |
| 297 | 301 | |
| 298 | 302 | /* |
| 299 | 303 | ** Reset or finalize a statement. |
| 300 | 304 | */ |
| 301 | 305 | int db_reset(Stmt *pStmt){ |
| 302 | 306 | int rc; |
| 303 | - db_stats(pStmt->pStmt); | |
| 307 | + db_stats(pStmt); | |
| 304 | 308 | rc = sqlite3_reset(pStmt->pStmt); |
| 305 | 309 | db_check_result(rc); |
| 306 | 310 | return rc; |
| 307 | 311 | } |
| 308 | 312 | int db_finalize(Stmt *pStmt){ |
| 309 | 313 | int rc; |
| 310 | - db_stats(pStmt->pStmt); | |
| 314 | + db_stats(pStmt); | |
| 311 | 315 | blob_reset(&pStmt->sql); |
| 312 | 316 | rc = sqlite3_finalize(pStmt->pStmt); |
| 313 | 317 | db_check_result(rc); |
| 314 | 318 | pStmt->pStmt = 0; |
| 315 | 319 | if( pStmt->pNext ){ |
| 316 | 320 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -54,10 +54,11 @@ | |
| 54 | */ |
| 55 | struct Stmt { |
| 56 | Blob sql; /* The SQL for this statement */ |
| 57 | sqlite3_stmt *pStmt; /* The results of sqlite3_prepare() */ |
| 58 | Stmt *pNext, *pPrev; /* List of all unfinalized statements */ |
| 59 | }; |
| 60 | #endif /* INTERFACE */ |
| 61 | |
| 62 | /* |
| 63 | ** Call this routine when a database error occurs. |
| @@ -197,10 +198,11 @@ | |
| 197 | zSql = blob_str(&pStmt->sql); |
| 198 | if( sqlite3_prepare_v2(g.db, zSql, -1, &pStmt->pStmt, 0)!=0 ){ |
| 199 | db_err("%s\n%s", sqlite3_errmsg(g.db), zSql); |
| 200 | } |
| 201 | pStmt->pNext = pStmt->pPrev = 0; |
| 202 | return 0; |
| 203 | } |
| 204 | int db_prepare(Stmt *pStmt, const char *zFormat, ...){ |
| 205 | int rc; |
| 206 | va_list ap; |
| @@ -272,44 +274,46 @@ | |
| 272 | ** or SQLITE_OK if the statement finishes successfully. |
| 273 | */ |
| 274 | int db_step(Stmt *pStmt){ |
| 275 | int rc; |
| 276 | rc = sqlite3_step(pStmt->pStmt); |
| 277 | return rc; |
| 278 | } |
| 279 | |
| 280 | /* |
| 281 | ** Print warnings if a query is inefficient. |
| 282 | */ |
| 283 | static void db_stats(sqlite3_stmt *pStmt){ |
| 284 | #ifdef FOSSIL_DEBUG |
| 285 | int c1, c2; |
| 286 | const char *zSql = sqlite3_sql(pStmt); |
| 287 | if( zSql==0 ) return; |
| 288 | c1 = sqlite3_stmt_status(pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, 1); |
| 289 | c2 = sqlite3_stmt_status(pStmt, SQLITE_STMTSTATUS_SORT, 1); |
| 290 | if( c1>5 && strstr(zSql,"/*scan*/")==0 ){ |
| 291 | fossil_warning("%d scan steps in [%s]", c1, zSql); |
| 292 | }else if( c2 && strstr(zSql,"/*sort*/")==0 && strstr(zSql,"/*scan*/")==0 ){ |
| 293 | fossil_warning("sort w/o index in [%s]", zSql); |
| 294 | } |
| 295 | #endif |
| 296 | } |
| 297 | |
| 298 | /* |
| 299 | ** Reset or finalize a statement. |
| 300 | */ |
| 301 | int db_reset(Stmt *pStmt){ |
| 302 | int rc; |
| 303 | db_stats(pStmt->pStmt); |
| 304 | rc = sqlite3_reset(pStmt->pStmt); |
| 305 | db_check_result(rc); |
| 306 | return rc; |
| 307 | } |
| 308 | int db_finalize(Stmt *pStmt){ |
| 309 | int rc; |
| 310 | db_stats(pStmt->pStmt); |
| 311 | blob_reset(&pStmt->sql); |
| 312 | rc = sqlite3_finalize(pStmt->pStmt); |
| 313 | db_check_result(rc); |
| 314 | pStmt->pStmt = 0; |
| 315 | if( pStmt->pNext ){ |
| 316 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -54,10 +54,11 @@ | |
| 54 | */ |
| 55 | struct Stmt { |
| 56 | Blob sql; /* The SQL for this statement */ |
| 57 | sqlite3_stmt *pStmt; /* The results of sqlite3_prepare() */ |
| 58 | Stmt *pNext, *pPrev; /* List of all unfinalized statements */ |
| 59 | int nStep; /* Number of sqlite3_step() calls */ |
| 60 | }; |
| 61 | #endif /* INTERFACE */ |
| 62 | |
| 63 | /* |
| 64 | ** Call this routine when a database error occurs. |
| @@ -197,10 +198,11 @@ | |
| 198 | zSql = blob_str(&pStmt->sql); |
| 199 | if( sqlite3_prepare_v2(g.db, zSql, -1, &pStmt->pStmt, 0)!=0 ){ |
| 200 | db_err("%s\n%s", sqlite3_errmsg(g.db), zSql); |
| 201 | } |
| 202 | pStmt->pNext = pStmt->pPrev = 0; |
| 203 | pStmt->nStep = 0; |
| 204 | return 0; |
| 205 | } |
| 206 | int db_prepare(Stmt *pStmt, const char *zFormat, ...){ |
| 207 | int rc; |
| 208 | va_list ap; |
| @@ -272,44 +274,46 @@ | |
| 274 | ** or SQLITE_OK if the statement finishes successfully. |
| 275 | */ |
| 276 | int db_step(Stmt *pStmt){ |
| 277 | int rc; |
| 278 | rc = sqlite3_step(pStmt->pStmt); |
| 279 | pStmt->nStep++; |
| 280 | return rc; |
| 281 | } |
| 282 | |
| 283 | /* |
| 284 | ** Print warnings if a query is inefficient. |
| 285 | */ |
| 286 | static void db_stats(Stmt *pStmt){ |
| 287 | #ifdef FOSSIL_DEBUG |
| 288 | int c1, c2; |
| 289 | const char *zSql = sqlite3_sql(pStmt->pStmt); |
| 290 | if( zSql==0 ) return; |
| 291 | c1 = sqlite3_stmt_status(pStmt->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, 1); |
| 292 | c2 = sqlite3_stmt_status(pStmt->pStmt, SQLITE_STMTSTATUS_SORT, 1); |
| 293 | if( c1>pStmt->nStep*4 && strstr(zSql,"/*scan*/")==0 ){ |
| 294 | fossil_warning("%d scan steps for %d rows in [%s]", c1, pStmt->nStep, zSql); |
| 295 | }else if( c2 && strstr(zSql,"/*sort*/")==0 && strstr(zSql,"/*scan*/")==0 ){ |
| 296 | fossil_warning("sort w/o index in [%s]", zSql); |
| 297 | } |
| 298 | pStmt->nStep = 0; |
| 299 | #endif |
| 300 | } |
| 301 | |
| 302 | /* |
| 303 | ** Reset or finalize a statement. |
| 304 | */ |
| 305 | int db_reset(Stmt *pStmt){ |
| 306 | int rc; |
| 307 | db_stats(pStmt); |
| 308 | rc = sqlite3_reset(pStmt->pStmt); |
| 309 | db_check_result(rc); |
| 310 | return rc; |
| 311 | } |
| 312 | int db_finalize(Stmt *pStmt){ |
| 313 | int rc; |
| 314 | db_stats(pStmt); |
| 315 | blob_reset(&pStmt->sql); |
| 316 | rc = sqlite3_finalize(pStmt->pStmt); |
| 317 | db_check_result(rc); |
| 318 | pStmt->pStmt = 0; |
| 319 | if( pStmt->pNext ){ |
| 320 |
+2
-2
| --- src/vfile.c | ||
| +++ src/vfile.c | ||
| @@ -324,11 +324,11 @@ | ||
| 324 | 324 | |
| 325 | 325 | db_must_be_within_tree(); |
| 326 | 326 | db_prepare(&q, |
| 327 | 327 | "SELECT %Q || pathname, pathname, file_is_selected(id), rid FROM vfile" |
| 328 | 328 | " WHERE NOT deleted AND vid=%d" |
| 329 | - " ORDER BY pathname", | |
| 329 | + " ORDER BY pathname /*scan*/", | |
| 330 | 330 | g.zLocalRoot, vid |
| 331 | 331 | ); |
| 332 | 332 | md5sum_init(); |
| 333 | 333 | while( db_step(&q)==SQLITE_ROW ){ |
| 334 | 334 | const char *zFullpath = db_column_text(&q, 0); |
| @@ -386,11 +386,11 @@ | ||
| 386 | 386 | |
| 387 | 387 | db_must_be_within_tree(); |
| 388 | 388 | |
| 389 | 389 | db_prepare(&q, "SELECT pathname, rid FROM vfile" |
| 390 | 390 | " WHERE NOT deleted AND rid>0 AND vid=%d" |
| 391 | - " ORDER BY pathname", | |
| 391 | + " ORDER BY pathname /*scan*/", | |
| 392 | 392 | vid); |
| 393 | 393 | blob_zero(&file); |
| 394 | 394 | md5sum_init(); |
| 395 | 395 | while( db_step(&q)==SQLITE_ROW ){ |
| 396 | 396 | const char *zName = db_column_text(&q, 0); |
| 397 | 397 |
| --- src/vfile.c | |
| +++ src/vfile.c | |
| @@ -324,11 +324,11 @@ | |
| 324 | |
| 325 | db_must_be_within_tree(); |
| 326 | db_prepare(&q, |
| 327 | "SELECT %Q || pathname, pathname, file_is_selected(id), rid FROM vfile" |
| 328 | " WHERE NOT deleted AND vid=%d" |
| 329 | " ORDER BY pathname", |
| 330 | g.zLocalRoot, vid |
| 331 | ); |
| 332 | md5sum_init(); |
| 333 | while( db_step(&q)==SQLITE_ROW ){ |
| 334 | const char *zFullpath = db_column_text(&q, 0); |
| @@ -386,11 +386,11 @@ | |
| 386 | |
| 387 | db_must_be_within_tree(); |
| 388 | |
| 389 | db_prepare(&q, "SELECT pathname, rid FROM vfile" |
| 390 | " WHERE NOT deleted AND rid>0 AND vid=%d" |
| 391 | " ORDER BY pathname", |
| 392 | vid); |
| 393 | blob_zero(&file); |
| 394 | md5sum_init(); |
| 395 | while( db_step(&q)==SQLITE_ROW ){ |
| 396 | const char *zName = db_column_text(&q, 0); |
| 397 |
| --- src/vfile.c | |
| +++ src/vfile.c | |
| @@ -324,11 +324,11 @@ | |
| 324 | |
| 325 | db_must_be_within_tree(); |
| 326 | db_prepare(&q, |
| 327 | "SELECT %Q || pathname, pathname, file_is_selected(id), rid FROM vfile" |
| 328 | " WHERE NOT deleted AND vid=%d" |
| 329 | " ORDER BY pathname /*scan*/", |
| 330 | g.zLocalRoot, vid |
| 331 | ); |
| 332 | md5sum_init(); |
| 333 | while( db_step(&q)==SQLITE_ROW ){ |
| 334 | const char *zFullpath = db_column_text(&q, 0); |
| @@ -386,11 +386,11 @@ | |
| 386 | |
| 387 | db_must_be_within_tree(); |
| 388 | |
| 389 | db_prepare(&q, "SELECT pathname, rid FROM vfile" |
| 390 | " WHERE NOT deleted AND rid>0 AND vid=%d" |
| 391 | " ORDER BY pathname /*scan*/", |
| 392 | vid); |
| 393 | blob_zero(&file); |
| 394 | md5sum_init(); |
| 395 | while( db_step(&q)==SQLITE_ROW ){ |
| 396 | const char *zName = db_column_text(&q, 0); |
| 397 |