PHP-MYSQL SELECT

时间:2015-08-20 20:25:20

标签: php mysql

我有一个PHP脚本,它使用mysqli方法向Amazon RDS实例发送查询。我注意到以下代码需要大约一分钟才能执行。我想知道它挂在哪里。

表非常大 - 超过3000万行。根据phpMyAdmin,它大约是8GB。它在与Web服务器相同的可用区和区域中的db.r3.large RDS实例上运行。我认为db.r3.large对此有点过分,但我想确保它不是问题。

我的脚本搜索用户名(全部或部分)并将匹配返回给jQuery前端。什么都没有超时 - 客户端浏览器等待[sitename] ..."然后返回时间信息以及结果。结果通常在十几到几百个匹配的行附近。

执行时间长是由于数据库的大小吗?我正确地检索和处理匹配吗?

当我手动运行查询时,phpMyAdmin使我的浏览器大约在同一时间(大约一分钟左右)等待黄色"正在加载"框然后返回相同的匹配,以及"显示行0 - 8(总计9,查询花费53.1656秒)"。

这是我的代码:

$mysqli = new mysqli($dbhost, $dbuser, $dbpass, $dbname);
$output = array();

if (mysqli_connect_errno()) {
  printf("Connect failed: %s\n", mysqli_connect_error());
  exit();
}

echo "Connected at " . getCurrentTime() . "<br><br>";

if ($result = $mysqli->query("SELECT * FROM tablename WHERE last_name LIKE \"%$query%\"")) {

echo "Loaded result at " . getCurrentTime() . "<br><br>";

$selected = $result->num_rows;

echo "Results ready at " . getCurrentTime() . "<br><br>";

while($row = $result->fetch_array(MYSQL_ASSOC)) {
  $output[] = $row;

  echo "Loaded into array at " . getCurrentTime() . "<br><br>";

/* close result set */
$result->close();

echo "Closed result at " . getCurrentTime() . "<br><br>";

}

} else {
  echo "No result at " . getCurrentTime() . "<br><br>";
}

/* close connection */
$mysqli->close();

echo "Closed mysqli at " . getCurrentTime() . "<br><br>";

以下是我的脚本输出的内容:

>Started at Thu Aug 20 19:56:08 2015
>
>Connected at Thu Aug 20 19:56:08 2015
>
>Loaded result at Thu Aug 20 19:57:01 2015
>
>Results ready at Thu Aug 20 19:57:01 2015
>
>Loaded into array at Thu Aug 20 19:57:01 2015
>
>Closed result at Thu Aug 20 19:57:01 2015
>
>Closed mysqli at Thu Aug 20 19:57:01 2015

(然后脚本返回结果的JSON编码对象。)

我可以访问RDS控制台和phpMyAdmin进行故障排除。

3 个答案:

答案 0 :(得分:2)

您的查询运行时间很长,因为它没有使用索引,因为通配符和LIKE比较。

LIKE "%$query%"

在此处阅读更多内容:http://dev.mysql.com/doc/refman/5.6/en/index-btree-hash.html

如果可以接受,您可以将查询更改为

LIKE "$query%"

虽然这会产生不同的结果,但它(至少应该)会创建更快的查询。

通配符远非理想!

答案 1 :(得分:2)

您不能在SQL中使用LIKE "%...%"查询,并期望从中获得良好的性能。像这样的主要通配符搜索意味着数据库必须扫描表中的每个记录才能找到匹配项。如果有很多匹配项,那么最终还是必须使用交换空间来存储查询结果。它永远不会很快;即使在中等大小的数据库上也可能太慢,而在像你这样的大型数据库上,它会非常缓慢。

你需要一种不同的方法。

有很多方法可以解决这个问题,这取决于您尝试做什么。如果您正在查找字符串中的关键字,那么您可以考虑将所有单词拉出到他们自己的记录中的单独表格中并进行搜索。你最终会得到一个有效的标记系统。

但通常情况下,像这样的搜索需要更多的力量。那么最好的解决方案通常是切换到专用数据索引工具,如SphinxLucene。这两种产品的工作方式略有不同,但实际上它们可以完成同样的工作:它们可以深入了解您的数据库,并生成一个全面的索引,您可以比更多更快地运行搜索。数据库可以提供的任何东西。

它们的设置和配置可能很复杂,但如果您希望进行这种灵活的搜索而不出现LIKE查询的性能问题,那么它们实际上是您唯一可行的方法。

答案 2 :(得分:1)

如果您使用var require = require("requirejs"); ,则每次运行查询时,它都会对所有3000万行进行完整比较。只能LIKE "%..%"缓存/编入索引。

如果您想在其中保留LIKE "...%",我认为您无法加快查询速度,但是,我有一些建议:

  • 使用LIKE "%..%"。你确定要输入亚历克斯与亚历克斯和亚历山大相匹配吗?
  • 制作自己的索引。创建一个包含最常见的姓氏和/或部分姓名及其ID的表。当用户不得不等待一分钟时,不是每次读取3000万行的值,而是创建一个在后台运行几个小时的脚本,构建一个包含30.000行的表,您可以在其中使用简单的{ {1}},可以编入索引,速度会快得多。 - 我猜。
  • 阅读数十个数据需要时间。确保您的表格没有100列您不需要使用或不使用WHERE last_name = :query的列。

请不要使用WHERE field = :query。 PHP的MySQLi API具有绑定值的功能:bind_param