diff --git a/includes/menu.inc b/includes/menu.inc
index 3a376f2..a9195c3 100644
--- a/includes/menu.inc
+++ b/includes/menu.inc
@@ -3590,42 +3590,41 @@ function _menu_router_build($callbacks) {
  * Helper function to save data from menu_router_build() to the router table.
  */
 function _menu_router_save($menu, $masks) {
-  // Delete the existing router since we have some data to replace it.
-  db_truncate('menu_router')->execute();
 
-  // Prepare insert object.
-  $insert = db_insert('menu_router')
-    ->fields(array(
-      'path',
-      'load_functions',
-      'to_arg_functions',
-      'access_callback',
-      'access_arguments',
-      'page_callback',
-      'page_arguments',
-      'delivery_callback',
-      'fit',
-      'number_parts',
-      'context',
-      'tab_parent',
-      'tab_root',
-      'title',
-      'title_callback',
-      'title_arguments',
-      'theme_callback',
-      'theme_arguments',
-      'type',
-      'description',
-      'position',
-      'weight',
-      'include_file',
-    ));
+  // These placeholders will be used in the SQL queries.
+  $field_placeholders = array(
+    'path'              => "'%s'",
+    'load_functions'    => "'%s'",
+    'to_arg_functions'  => "'%s'",
+    'access_callback'   => "'%s'",
+    'access_arguments'  => "'%s'",
+    'page_callback'     => "'%s'",
+    'page_arguments'    => "'%s'",
+    'delivery_callback' => "'%s'",  // new in D7
+    'fit'               => '%d',
+    'number_parts'      => '%d',
+    'context'           => "'%s'",  // new in D7
+    'tab_parent'        => "'%s'",
+    'tab_root'          => "'%s'",
+    'title'             => "'%s'",
+    'title_callback'    => "'%s'",
+    'title_arguments'   => "'%s'",
+    'theme_callback'    => "'%s'",  // new in D7
+    'theme_arguments'   => "'%s'",  // new in D7
+    'type'              => '%d',
+    // 'block_callback'    => "'%s'",  // gone in D7
+    'description'       => "'%s'",
+    'position'          => "'%s'",
+    'weight'            => '%d',
+    // 'file'              => "'%s'",  // gone in D7
+    'include_file'      => "'%s'",  // new in D7
+  );
 
-  $num_records = 0;
+  $field_names = array_keys($field_placeholders);
 
+  // rewrite some field values
   foreach ($menu as $path => $item) {
-    // Fill in insert object values.
-    $insert->values(array(
+    $menu[$path] = array(
       'path' => $item['path'],
       'load_functions' => $item['load_functions'],
       'to_arg_functions' => $item['to_arg_functions'],
@@ -3649,17 +3648,83 @@ function _menu_router_save($menu, $masks) {
       'position' => $item['position'],
       'weight' => $item['weight'],
       'include_file' => $item['include file'],
-    ));
+    );
+  }
+
+  // Determine the diff of new and old table contents.
+  $delete = array();
+  $update = array();
+  $insert = $menu;
+
+  $q = db_select('menu_router')
+    ->fields('menu_router')
+    ->execute();
 
-    // Execute in batches to avoid the memory overhead of all of those records
-    // in the query object.
-    if (++$num_records == 20) {
-      $insert->execute();
-      $num_records = 0;
+  while ($row_old = $q->fetchAssoc()) {
+    $path = $row_old['path'];
+    if (!isset($menu[$path])) {
+      $delete[$path] = TRUE;
     }
+    else {
+      // Compare the old row with the new row.
+      $row_changes = array();
+      foreach ($row_old as $key => $value_old) {
+        if ($menu[$path][$key] != $value_old) {
+          $row_changes[$key] = $menu[$path][$key];
+        }
+      }
+      if (count($row_changes)) {
+        $update[$path] = $row_changes;
+      }
+    }
+    unset($insert[$path]);
+  }
+
+  // Save the changes.
+
+  // Delete rows that no longer exist.
+  if ($n_delete = count($delete)) {
+    db_delete('menu_router')
+      ->condition('path', array_keys($delete))
+      ->execute();
+  }
+
+  // Update rows that have changed.
+  if ($n_update = count($update)) {
+    foreach ($update as $path => $row_changes) {
+      db_update('menu_router')
+        ->fields($row_changes)
+        ->condition('path', $path)
+        ->execute();
+    }
+  }
+
+  // Insert new rows, in chunks of 20.
+  if ($n_insert = count($insert)) {
+
+    // Prepare insert object.
+    $q = db_insert('menu_router')
+      ->fields($field_names);
+
+    $num_records = 0;
+
+    foreach ($insert as $path => $item) {
+
+      // Fill in insert object values.
+      $q->values($item);
+
+      // Execute in batches to avoid the memory overhead of all of those records
+      // in the query object.
+      if (++$num_records == 20) {
+        $q->execute();
+        $num_records = 0;
+      }
+    }
+
+    // Insert any remaining records.
+    $q->execute();
   }
-  // Insert any remaining records.
-  $insert->execute();
+
   // Store the masks.
   variable_set('menu_masks', $masks);
 
