On one CollabNet's forums a user reported that a single delete command of 2000+ WC files took well over three hours to complete with 1.7.5 (see http://subversion.open.collab.net/ds/viewMessage.do?dsForumId=4&dsMessageId=456214).
I'm able to replicate similar behavior with a partial checkout of ^/subversion/tags My test WC: WC Size: 437 MB 21,012 Files, 2,717 Folders wc.db Size: 18,108,000 bytes Deletion Targets: 2642 files Using 1.7.5 this takes almost 27 minutes on my machine: C:\SVN\sandbox\subversion-tags>timethis svn delete -q --targets del-target.2463.txt TimeThis : Command Line : svn delete -q --targets del-target.2463.txt TimeThis : Start Time : Fri May 18 11:27:04 2012 TimeThis : Command Line : svn delete -q --targets del-target.2463.txt TimeThis : Start Time : Fri May 18 11:27:04 2012 TimeThis : End Time : Fri May 18 11:53:58 2012 TimeThis : Elapsed Time : 00:26:53.758 trunk@1341851 is significantly faster, taking only 16 minutes: C:\SVN\sandbox\subversion-tags>timethis svn delete -q --targets del-target.2463.txt TimeThis : Command Line : svn delete -q --targets del-target.2463.txt TimeThis : Start Time : Wed May 23 10:56:41 2012 TimeThis : Command Line : svn delete -q --targets del-target.2463.txt TimeThis : Start Time : Wed May 23 10:56:41 2012 TimeThis : End Time : Wed May 23 11:13:17 2012 TimeThis : Elapsed Time : 00:16:35.873 Using optimizations similar to what Bert used in r1341848 and creating a new , the attach patch cuts this down to just over 4 seconds: C:\SVN\sandbox\subversion-tags>timethis svn delete -q --targets del-target.2463.txt TimeThis : Command Line : svn delete -q --targets del-target.2463.txt TimeThis : Start Time : Wed May 23 17:41:12 2012 TimeThis : Command Line : svn delete -q --targets del-target.2463.txt TimeThis : Start Time : Wed May 23 17:41:12 2012 TimeThis : End Time : Wed May 23 17:41:16 2012 TimeThis : Elapsed Time : 00:00:04.116 ...So, WCNG gurus, does this look ok? [[[ Speed up WC deletions. * subversion/libsvn_wc/wc-queries.sql (STMT_DELETE_NODES_ABOVE_DEPTH_RECURSIVE, STMT_INSERT_DELETE_FROM_NODE_RECURSIVE): Make the OR operation the outer operation by duplicating some cheap tests. (STMT_INSERT_DELETE_LIST_RECURSIVE, STMT_INSERT_DELETE_LIST): Split old STMT_INSERT_DELETE_LIST into two new versions, one recursive, and one not. * subversion/libsvn_wc/wc_db.c (delete_node): Use the faster non-recursive query when operating on a file. ]]] -- Paul T. Burba CollabNet, Inc. -- www.collab.net -- Enterprise Cloud Development Skype: ptburba
Index: subversion/libsvn_wc/wc-queries.sql =================================================================== --- subversion/libsvn_wc/wc-queries.sql (revision 1342072) +++ subversion/libsvn_wc/wc-queries.sql (working copy) @@ -587,11 +587,15 @@ WHERE wc_id = ?1 AND local_relpath = ?2 -- STMT_DELETE_NODES_ABOVE_DEPTH_RECURSIVE +/* ### The Sqlite optimizer needs help here ### + * WHERE wc_id = ?1 + * AND (local_relpath = ?2 + * OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2)) + * AND op_depth >= ?3 */ DELETE FROM nodes -WHERE wc_id = ?1 - AND (local_relpath = ?2 - OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2)) - AND op_depth >= ?3 +WHERE (wc_id = ?1 AND local_relpath = ?2 AND op_depth >= ?3) + OR (wc_id = ?1 AND IS_STRICT_DESCENDANT_OF(local_relpath, ?2) + AND op_depth >= ?3) -- STMT_DELETE_ACTUAL_NODE DELETE FROM actual_node @@ -828,16 +832,25 @@ /* If this query is updated, STMT_INSERT_DELETE_LIST should too. */ -- STMT_INSERT_DELETE_FROM_NODE_RECURSIVE +/* ### The Sqlite optimizer needs help here ### + * WHERE wc_id = ?1 + * AND (local_relpath = ?2 + * OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2)) + * AND op_depth = ?3 + * AND presence NOT IN ('base-deleted', 'not-present', 'excluded', + * 'absent') */ INSERT INTO nodes ( wc_id, local_relpath, op_depth, parent_relpath, presence, kind) SELECT wc_id, local_relpath, ?4 /*op_depth*/, parent_relpath, 'base-deleted', kind FROM nodes -WHERE wc_id = ?1 - AND (local_relpath = ?2 - OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2)) - AND op_depth = ?3 - AND presence NOT IN ('base-deleted', 'not-present', 'excluded', 'absent') +WHERE (wc_id = ?1 AND local_relpath = ?2 AND op_depth = ?3 + AND presence NOT IN ('base-deleted', 'not-present', 'excluded', + 'absent')) + OR (wc_id = ?1 AND IS_STRICT_DESCENDANT_OF(local_relpath, ?2) + AND op_depth = ?3 + AND presence NOT IN ('base-deleted', 'not-present', 'excluded', + 'absent')) -- STMT_INSERT_WORKING_NODE_FROM_BASE_COPY INSERT INTO nodes ( @@ -1229,7 +1242,7 @@ /* This matches the selection in STMT_INSERT_DELETE_FROM_NODE_RECURSIVE. A subquery is used instead of nodes_current to avoid a table scan */ --- STMT_INSERT_DELETE_LIST +-- STMT_INSERT_DELETE_LIST_RECURSIVE INSERT INTO delete_list(local_relpath) SELECT local_relpath FROM nodes AS n WHERE wc_id = ?1 @@ -1241,6 +1254,17 @@ AND s.local_relpath = n.local_relpath) AND presence NOT IN ('base-deleted', 'not-present', 'excluded', 'absent') +-- STMT_INSERT_DELETE_LIST +INSERT INTO delete_list(local_relpath) +SELECT local_relpath FROM nodes AS n +WHERE wc_id = ?1 + AND (local_relpath = ?2) + AND op_depth >= ?3 + AND op_depth = (SELECT MAX(s.op_depth) FROM nodes AS s + WHERE s.wc_id = ?1 + AND s.local_relpath = n.local_relpath) + AND presence NOT IN ('base-deleted', 'not-present', 'excluded', 'absent') + -- STMT_SELECT_DELETE_LIST SELECT local_relpath FROM delete_list ORDER BY local_relpath Index: subversion/libsvn_wc/wc_db.c =================================================================== --- subversion/libsvn_wc/wc_db.c (revision 1342072) +++ subversion/libsvn_wc/wc_db.c (working copy) @@ -6728,8 +6728,15 @@ } /* ### Put actual-only nodes into the list? */ - SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, - STMT_INSERT_DELETE_LIST)); + /* If LOCAL_RELPATH at SELECT_DEPTH is a file we can use + the (faster) non-recursive query. */ + if (kind == svn_kind_file) + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_INSERT_DELETE_LIST)); + else + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_INSERT_DELETE_LIST_RECURSIVE)); + SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath, select_depth)); SVN_ERR(svn_sqlite__step_done(stmt));