diff -urN drupal-7.x-dev/includes/database/mysql/pager.inc drupal-7.x-dev-hints/includes/database/mysql/pager.inc
--- /includes/database/mysql/pager.inc	1970-01-01 10:00:00.000000000 +1000
+++ includes/database/mysql/pager.inc	2010-05-20 17:47:39.245538641 +1000
@@ -0,0 +1,101 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Functions to aid in presenting mysql database results as a set of pages.
+ */
+
+
+/**
+ * Query extender for mysql pager queries.
+ *
+ * This is the mysql specific pager mechanism.  It creates a paged query with a fixed
+ * number of entries per page and simultaneously counts the total number of rows.
+ */
+class PagerDefault_mysql extends PagerDefault {
+
+  /**
+   * Override the execute method.
+   *
+   * Before we run the query, we need to add pager-based range() instructions
+   * to it.
+   */
+  public function execute() {
+    global $pager_page_array, $pager_total, $pager_total_items, $pager_limits;
+
+    // Add convenience tag to mark that this is an extended query. We have to
+    // do this in the constructor to ensure that it is set before preExecute()
+    // gets called.
+    if (!$this->preExecute($this)) {
+      return NULL;
+    }
+
+    // A NULL limit is the "kill switch" for pager queries.
+    if (empty($this->limit)) {
+      return;
+    }
+    $this->ensureElement();
+
+    $page = isset($_GET['page']) ? $_GET['page'] : '';
+
+    // Convert comma-separated $page to an array, used by other functions.
+    $pager_page_array = explode(',', $page);
+
+    if (!isset($pager_page_array[$this->element])) {
+      $pager_page_array[$this->element] = 0;
+    }
+
+    // Rather than rely on the countQuery, add a query hint to prepare for a
+    // FOUND_ROWS() call a bit later on. That means we don't need to load the
+    // entire table index twice, which should see a nice speed increase when
+    // paging through large tables, esepecially on InnoDB.
+    //
+    $this->query->setHints('SQL_CALC_FOUND_ROWS');
+
+    // We usually calculate the total number of pages as ceil(items / limit) but
+    // now that we don't run a coutnQuery, we don't know the total number of rows
+    // before running the pager_query. For now we assume that the total items is
+    // the current page number multiplied by the limit. We recalculate when we
+    // know the correct total number.
+    //
+    $this->range((int)$page * $this->limit, $this->limit);
+
+    // Now that we've added our pager-based range instructions, run the query
+    // normally.
+    $result = $this->query->execute();
+
+    // And now we can fetch the total number of results, had there not been
+    // a range.
+    $pager_total_items[$this->element] = $this->connection->query('SELECT FOUND_ROWS()')->fetchField();
+
+    // This does unfortunately mean that a user can override the page variable
+    // in the query string and end up with an empty pager. Previously this would
+    // make this default to the last page. We can emulate this behaviour by
+    // checking the total number of rows returned and re-run an adjusted query
+    // in that case.
+    //
+    // What we do now is check if our query range was out of bounds, which can
+    // happen if the user manually overrode the page variable in the query
+    // string. If no rows were returned and if we're not looking at the first
+    // page of this pager, adjust the range to return the last page of results
+    // only, just as we would normally do.
+    //
+    if (((int)$page * $this->limit) > $pager_total_items[$this->element] && (int)$page) {
+      // Calculate the new range and re-run the pager query to return the last
+      // page of results.
+      $page_max = ceil($pager_total_items[$this->element] / $this->limit) - 1;
+      $this->range($page_max * $this->limit, $this->limit);
+      // No need to re-count all rows, so remove the hint.
+      $this->query->setHints('');
+      $result = $this->query->execute();
+    }
+
+    // Redo the page number calculation, because we now know the total humber of results.
+    $pager_total[$this->element] = ceil($pager_total_items[$this->element] / $this->limit);
+    $pager_page_array[$this->element] = max(0, min((int)$pager_page_array[$this->element], ((int)$pager_total[$this->element]) - 1));
+    $pager_limits[$this->element] = $this->limit;
+
+    return $result;
+  }
+}
diff -urN drupal-7.x-dev/includes/database/mysql/query.inc drupal-7.x-dev-hints/includes/database/mysql/query.inc
--- includes/database/mysql/query.inc	2010-05-15 17:04:21.000000000 +1000
+++ includes/database/mysql/query.inc	2010-05-20 17:03:23.905537094 +1000
@@ -46,16 +46,19 @@
     // Create a comments string to prepend to the query.
     $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : '';
 
+    // Create a hints string to include in the query.
+    $hints = (!empty($this->hints)) ? $this->hints . ' ' : '';
+
     // Default fields are always placed first for consistency.
     $insert_fields = array_merge($this->defaultFields, $this->insertFields);
 
     // If we're selecting from a SelectQuery, finish building the query and
     // pass it back, as any remaining options are irrelevant.
     if (!empty($this->fromQuery)) {
-      return $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') ' . $this->fromQuery;
+      return $comments . 'INSERT ' . $hints . 'INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') ' . $this->fromQuery;
     }
 
-    $query = $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') VALUES ';
+    $query = $comments . 'INSERT ' . $hints . 'INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') VALUES ';
 
     $max_placeholder = 0;
     $values = array();
@@ -148,6 +151,9 @@
     // Create a comments string to prepend to the query.
     $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : '';
 
+    // Create a hints string to include in the query.
+    $hints = (!empty($this->hints)) ? $this->hints . ' ' : '';
+
     // Set defaults.
     if ($this->updateFields) {
       $update_fields = $this->updateFields;
@@ -168,7 +174,7 @@
 
     $insert_fields = $this->insertFields + $this->keyFields;
 
-    $query = $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', array_keys($insert_fields)) . ') VALUES ';
+    $query = $comments . 'INSERT ' . $hints . 'INTO {' . $this->table . '} (' . implode(', ', array_keys($insert_fields)) . ') VALUES ';
 
     $max_placeholder = 0;
     $values = array();
@@ -205,6 +211,121 @@
   }
 }
 
+class SelectQuery_mysql extends SelectQuery {
+
+  /**
+   * Override this for SelectQuery_mysql to include support for query hints.
+   */
+  public function __toString() {
+    // Create a comments string to prepend to the query.
+    $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : '';
+
+    // Create a hints string to include in the query.
+    $hints = (!empty($this->hints)) ? $this->hints . ' ' : '';
+
+    // SELECT
+    $query = $comments . 'SELECT ' . $hints;
+
+    if ($this->distinct) {
+      $query .= 'DISTINCT ';
+    }
+
+    // FIELDS and EXPRESSIONS
+    $fields = array();
+    foreach ($this->tables as $alias => $table) {
+      if (!empty($table['all_fields'])) {
+        $fields[] = $alias . '.*';
+      }
+    }
+    foreach ($this->fields as $alias => $field) {
+      // Always use the AS keyword for field aliases, as some
+      // databases require it (e.g., PostgreSQL).
+      $fields[] = (isset($field['table']) ? $field['table'] . '.' : '') . $field['field'] . ' AS ' . $field['alias'];
+    }
+    foreach ($this->expressions as $alias => $expression) {
+      $fields[] = $expression['expression'] . ' AS ' . $expression['alias'];
+    }
+    $query .= implode(', ', $fields);
+
+
+    // FROM - We presume all queries have a FROM, as any query that doesn't won't need the query builder anyway.
+    $query .= "\nFROM ";
+    foreach ($this->tables as $alias => $table) {
+      $query .= "\n";
+      if (isset($table['join type'])) {
+        $query .= $table['join type'] . ' JOIN ';
+      }
+
+      // If the table is a subquery, compile it and integrate it into this query.
+      if ($table['table'] instanceof SelectQueryInterface) {
+        // Run preparation steps on this sub-query before converting to string.
+        $subquery = $table['table'];
+        $subquery->preExecute();
+        $table_string = '(' . (string) $subquery . ')';
+      }
+      else {
+        $table_string = '{' . $this->connection->escapeTable($table['table']) . '}';
+      }
+
+      // Don't use the AS keyword for table aliases, as some
+      // databases don't support it (e.g., Oracle).
+      $query .=  $table_string . ' ' . $table['alias'];
+
+      if (!empty($table['condition'])) {
+        $query .= ' ON ' . $table['condition'];
+      }
+    }
+
+    // WHERE
+    if (count($this->where)) {
+      $this->where->compile($this->connection, $this);
+      // There is an implicit string cast on $this->condition.
+      $query .= "\nWHERE " . $this->where;
+    }
+
+    // GROUP BY
+    if ($this->group) {
+      $query .= "\nGROUP BY " . implode(', ', $this->group);
+    }
+
+    // HAVING
+    if (count($this->having)) {
+      $this->having->compile($this->connection, $this);
+      // There is an implicit string cast on $this->having.
+      $query .= "\nHAVING " . $this->having;
+    }
+
+    // ORDER BY
+    if ($this->order) {
+      $query .= "\nORDER BY ";
+      $fields = array();
+      foreach ($this->order as $field => $direction) {
+        $fields[] = $field . ' ' . $direction;
+      }
+      $query .= implode(', ', $fields);
+    }
+
+    // RANGE
+    // There is no universal SQL standard for handling range or limit clauses.
+    // Fortunately, all core-supported databases use the same range syntax.
+    // Databases that need a different syntax can override this method and
+    // do whatever alternate logic they need to.
+    if (!empty($this->range)) {
+      $query .= "\nLIMIT " . $this->range['length'] . " OFFSET " . $this->range['start'];
+    }
+
+    // UNION is a little odd, as the select queries to combine are passed into
+    // this query, but syntactically they all end up on the same level.
+    if ($this->union) {
+      foreach ($this->union as $union) {
+        $query .= ' ' . $union['type'] . ' ' . (string) $union['query'];
+      }
+    }
+
+    return $query;
+  }
+}
+
 /**
  * @} End of "ingroup database".
  */
diff -urN drupal-7.x-dev/includes/database/query.inc drupal-7.x-dev-hints/includes/database/query.inc
--- includes/database/query.inc	2010-05-15 17:04:21.000000000 +1000
+++ includes/database/query.inc	2010-05-20 17:35:08.246024892 +1000
@@ -247,6 +247,13 @@
    */
   protected $comments = array();
 
+  /**
+   * Query hints or flags that can be set on a query.
+   *
+   * @var string
+   */
+  protected $hints = '';
+
   public function __construct(DatabaseConnection $connection, $options) {
     $this->connection = $connection;
     $this->queryOptions = $options;
@@ -308,6 +315,20 @@
   public function &getComments() {
     return $this->comments;
   }
+
+  /**
+   * Sets the hints or flags on a query.
+   *
+   * Hints and flags directly affect the way in which the query is run
+   * on the database server. Their syntax is database specific, so they
+   * should be used internally in database-specific classes only.
+   *
+   * @param $hints
+   *   The hint string to be inserted into the query.
+   */
+  public function setHints($hints) {
+    $this->hints = $hints;
+  }
 }
 
 /**
