如何优化嵌套查询的数据库连接?

时间:2015-02-05 12:47:44

标签: php mysql mysqli

我使用嵌套查询从多个表中检索信息。我需要有关优化此PHP代码的建议。

此函数创建一个对象。

public function conn($query){

 $mysqli = new mysqli('test','test','test','test');
 $result = $mysqli->query("SET NAMES utf8");
 $result = $mysqli->query("set character_set_client='utf8'");
 $result = $mysqli->query("set collation_connection='utf8_general_ci'");
 $result = $mysqli->query($query);
 $mysqli->close();
 return $result;
}

此代码使用该功能。

$connect = $this->conn("SELECT * FROM Table LIMIT 100000");
while($i = $connect->fetch_assoc()){
  $name =  $i["name"];
  $connect2 = $this->conn("SELECT * FROM Names WHERE Name = '$name'");
  if($connect2 ->num_rows > 0){
    echo $name.'<br>';
  }
}

需要建议连接数据库。

while循环中,如您所见,我正在检查其他表中是否存在$name。但我每次通过循环打开和关闭连接。这将是100001连接打开和关闭。

是否可以只打开一次与数据库的连接?

P.S。:SQL是一个例子 - 请不要在那里建议更改,因为我试图弄清楚如何处理重复的查询,而不是优化SQL。

1 个答案:

答案 0 :(得分:3)

连接对象是可重用的。建立连接,然后使用它来生成任意数量的查询。完成后关闭每个查询(即每个结果集),然后在运行结束时关闭连接。

关闭连接是网络操作,因此需要一段时间。关闭查询主要是内存操作,因此速度更快。

在您的示例中,您正在使用嵌套查询(稍后会详细介绍)。您的代码最终应该看起来像这样的伪代码:

public function getconn(){
 $mysqli = new mysqli('test','test','test','test');
 $mysqli->query("SET NAMES utf8");
 $mysqli->query("set character_set_client='utf8'");
 $mysqli->query("set collation_connection='utf8_general_ci'");
 return $mysqli;  /* return the connection handle */
}

$conn1 = getconn();
$conn2 = getconn();
$resultset1 = $conn1->query("SELECT * FROM Table LIMIT 100000");
while($i = $resultset1->fetch_assoc()){
  $name =  $i["name"];
  $resultset2 = $conn2->query("SELECT * FROM Names WHERE Name = '$name'");
  if($resultset2->num_rows > 0){
    echo $name.'<br>';
  }
  $resultset2->close();
}
$resultset1->close();
$conn1->close();
$conn2->close();

(请注意;我没有调试此代码。)

要进一步采用此优化,您应该考虑在while循环内为查询使用预准备语句。这是关于http://php.net/manual/en/mysqli-stmt.fetch.php的文档。

$conn1 = getconn();
$conn2 = getconn();

/* create a prepared statement with placeholder parameter ? */
$stmt = $mysqli->prepare("SELECT * FROM Name WHERE Name = ?"));
$name = '';
$name_out = '';
$stmt->bind_param("s", $name);
$stmt->bind_result($name_out);

$resultset1 = $conn1->query("SELECT * FROM Table LIMIT 100000");
while($i = $resultset1->fetch_assoc()){
  $name =  $i["name"];
  $resultset2 = $stmt->execute(); /* run query with bound parameter */
  if ($stmt_fetch() ( {
    echo $name.'<br>';
  }
  $resultset2->close();
}
$resultset1->close();
$conn1->close();
$conn2->close();

(请注意;我也没有调试过此代码。) 现在,您的查询对可能只是一个显示一组嵌套查询的示例。如果是这样,那没关系。但是,您正在以几乎无法想象的低效方式执行此任务(检索100K名称)。你已经说过你不想让任何人重写这个查询,但很抱歉,我不能让这个通过。

此代码可以更加简化工作。

$conn = getconn();
$q = "SELECT t.name FROM Table t JOIN Name n ON t.name = n.name LIMIT 100000";
$resultset = $conn->query($q);
while($i = $resultset->fetch_assoc()){
    $name =  $i["name"];
    echo $name.'<br>';
}
$resultset->close();
$conn->close();

由于两个原因,效率更高。首先,它不使用SELECT *,它最终通过网络将各种数据从MySQL服务器发送到您的php程序,只是为了扔掉它。

其次,它不使用嵌套查询。相反,JOIN查询会从name中提取Tablename列中Names列的所有{{1}}列。