Add explain method to query builder

This commit is contained in:
Timothy Warren 2014-02-04 20:59:30 -05:00
parent 6dc9ed0d52
commit 8dc2079d43
14 changed files with 212 additions and 11 deletions

View File

@ -31,6 +31,14 @@ interface iDB_SQL {
* @return string * @return string
*/ */
public function limit($sql, $limit, $offset=FALSE); public function limit($sql, $limit, $offset=FALSE);
/**
* Modify the query to get the query plan
*
* @param string $sql
* @return string
*/
public function explain($sql);
/** /**
* Get the sql for random ordering * Get the sql for random ordering
@ -113,4 +121,4 @@ interface iDB_SQL {
public function column_list($table); public function column_list($table);
} }
// End of db_sql.php // End of db_sql.php

View File

@ -85,6 +85,15 @@ interface iQuery_Builder {
* @return $this * @return $this
*/ */
public function distinct(); public function distinct();
// --------------------------------------------------------------------------
/**
* Shows the query plan for the query
*
* @return $this
*/
public function explain();
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -181,9 +190,10 @@ interface iQuery_Builder {
* *
* @param mixed $key * @param mixed $key
* @param mixed $val * @param mixed $val
@ @param bool $escape
* @return $this * @return $this
*/ */
public function where($key, $val=array()); public function where($key, $val=array(), $escape = NULL);
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------

View File

@ -92,6 +92,9 @@ class Query_Builder implements iQuery_Builder {
// List of sql queries executed // List of sql queries executed
public $queries; public $queries;
// Whether to do only an explain on the query
protected $explain = FALSE;
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// ! Methods // ! Methods
@ -267,6 +270,19 @@ class Query_Builder implements iQuery_Builder {
$this->select_string = ' DISTINCT '.$this->select_string; $this->select_string = ' DISTINCT '.$this->select_string;
return $this; return $this;
} }
// --------------------------------------------------------------------------
/**
* Tell the database to give you the query plan instead of result set
*
* @return $this
*/
public function explain()
{
$this->explain = TRUE;
return $this;
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -593,9 +609,10 @@ class Query_Builder implements iQuery_Builder {
* *
* @param mixed $key * @param mixed $key
* @param mixed $val * @param mixed $val
* @param mixed $escape
* @return $this * @return $this
*/ */
public function where($key, $val=array()) public function where($key, $val=array(), $escape=NULL)
{ {
return $this->_where_string($key, $val, 'AND'); return $this->_where_string($key, $val, 'AND');
} }
@ -1382,8 +1399,14 @@ class Query_Builder implements iQuery_Builder {
{ {
$sql = $this->sql->limit($sql, $this->limit, $this->offset); $sql = $this->sql->limit($sql, $this->limit, $this->offset);
} }
// See what needs to happen to only return the query plan
if (isset($this->explain) && $this->explain === TRUE)
{
$sql = $this->sql->explain($sql);
}
return $sql; return $sql;
} }
} }
// End of query_builder.php // End of query_builder.php

View File

@ -45,6 +45,19 @@ class Firebird_SQL implements iDB_SQL {
return $sql; return $sql;
} }
// --------------------------------------------------------------------------
/**
* Get the query plan for the sql query
*
* @param string $sql
* @return string
*/
public function explain($sql)
{
return $sql;
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -255,4 +268,4 @@ SQL;
} }
} }
//End of firebird_sql.php //End of firebird_sql.php

View File

@ -65,4 +65,4 @@ class MySQL extends DB_PDO {
$this->query("TRUNCATE `{$table}`"); $this->query("TRUNCATE `{$table}`");
} }
} }
//End of mysql_driver.php //End of mysql_driver.php

View File

@ -38,6 +38,19 @@ class MySQL_SQL implements iDB_SQL {
return $sql." LIMIT {$offset}, {$limit}"; return $sql." LIMIT {$offset}, {$limit}";
} }
// --------------------------------------------------------------------------
/**
* Get the query plan for the sql query
*
* @param string $sql
* @return string
*/
public function explain($sql)
{
return "EXPLAIN EXTENDED {$sql}";
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -178,4 +191,4 @@ class MySQL_SQL implements iDB_SQL {
return "SHOW FULL COLUMNS FROM {$table}"; return "SHOW FULL COLUMNS FROM {$table}";
} }
} }
//End of mysql_sql.php //End of mysql_sql.php

View File

@ -70,4 +70,4 @@ class ODBC extends DB_PDO {
return NULL; return NULL;
} }
} }
// End of odbc_driver.php // End of odbc_driver.php

View File

@ -33,6 +33,19 @@ class ODBC_SQL implements iDB_SQL {
{ {
return $sql; return $sql;
} }
// --------------------------------------------------------------------------
/**
* Get the query plan for the sql query
*
* @param string $sql
* @return string
*/
public function explain($sql)
{
return $sql;
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -168,4 +181,4 @@ class ODBC_SQL implements iDB_SQL {
} }
} }
// End of odbc_sql.php // End of odbc_sql.php

View File

@ -39,6 +39,19 @@ class PgSQL_SQL implements iDB_SQL {
return $sql; return $sql;
} }
// --------------------------------------------------------------------------
/**
* Get the query plan for the sql query
*
* @param string $sql
* @return string
*/
public function explain($sql)
{
return "EXPLAIN VERBOSE {$sql}";
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -227,4 +240,4 @@ SQL;
SQL; SQL;
} }
} }
//End of pgsql_manip.php //End of pgsql_manip.php

View File

@ -38,6 +38,19 @@ class SQLite_SQL implements iDB_SQL {
return $sql." LIMIT {$offset}, {$limit}"; return $sql." LIMIT {$offset}, {$limit}";
} }
// --------------------------------------------------------------------------
/**
* Get the query plan for the sql query
*
* @param string $sql
* @return string
*/
public function explain($sql)
{
return "EXPLAIN QUERY PLAN {$sql}";
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -180,4 +193,4 @@ SQL;
} }
} }
//End of sqlite_sql.php //End of sqlite_sql.php

View File

@ -90,4 +90,5 @@ class FirebirdQBTest extends QBTest {
$this->assertTrue(is_array($res)); $this->assertTrue(is_array($res));
} }
} }

View File

@ -49,4 +49,35 @@ class MySQLQBTest extends QBTest {
{ {
$this->assertTrue(in_array('mysql', PDO::getAvailableDrivers())); $this->assertTrue(in_array('mysql', PDO::getAvailableDrivers()));
} }
// --------------------------------------------------------------------------
public function testQueryExplain()
{
$query = $this->db->select('id, key as k, val')
->explain()
->where('id >', 1)
->where('id <', 900)
->get('create_test', 2, 1);
$res = $query->fetchAll(PDO::FETCH_ASSOC);
$expected = array (
array (
'id' => '1',
'select_type' => 'SIMPLE',
'table' => 'create_test',
'type' => 'range',
'possible_keys' => 'PRIMARY',
'key' => 'PRIMARY',
'key_len' => '4',
'ref' => NULL,
'rows' => '1',
'filtered' => '100.00',
'Extra' => 'Using where',
)
);
$this->assertEqual($expected, $res);
}
} }

View File

@ -48,4 +48,43 @@ class PgSQLQBTest extends QBTest {
{ {
$this->assertTrue(in_array('pgsql', PDO::getAvailableDrivers())); $this->assertTrue(in_array('pgsql', PDO::getAvailableDrivers()));
} }
// --------------------------------------------------------------------------
public function testQueryExplain()
{
$query = $this->db->select('id, key as k, val')
->explain()
->where('id >', 1)
->where('id <', 900)
->get('create_test', 2, 1);
$res = $query->fetchAll(PDO::FETCH_ASSOC);
$expected = array (
array (
'QUERY PLAN' => 'Limit (cost=6.41..10.64 rows=2 width=68)',
),
array (
'QUERY PLAN' => ' Output: id, key, val',
),
array (
'QUERY PLAN' => ' -> Bitmap Heap Scan on public.create_test (cost=4.29..12.76 rows=4 width=68)',
),
array (
'QUERY PLAN' => ' Output: id, key, val',
),
array (
'QUERY PLAN' => ' Recheck Cond: ((create_test.id > 1) AND (create_test.id < 900))',
),
array (
'QUERY PLAN' => ' -> Bitmap Index Scan on create_test_pkey (cost=0.00..4.29 rows=4 width=0)',
),
array (
'QUERY PLAN' => ' Index Cond: ((create_test.id > 1) AND (create_test.id < 900))',
),
);
$this->assertEqual($expected, $res);
}
} }

View File

@ -60,4 +60,28 @@
$this->assertNull($query); $this->assertNull($query);
} }
// --------------------------------------------------------------------------
public function testQueryExplain()
{
$query = $this->db->select('id, key as k, val')
->explain()
->where('id >', 1)
->where('id <', 900)
->get('create_test', 2, 1);
$res = $query->fetchAll(PDO::FETCH_ASSOC);
$expected = array (
array (
'selectid' => '0',
'order' => '0',
'from' => '0',
'detail' => 'SEARCH TABLE create_test USING INTEGER PRIMARY KEY (rowid>? AND rowid<?)',
),
);
$this->assertEqual($expected, $res);
}
} }