簡體   English   中英

PHP-MYSQL SELECT中的查詢時間長

[英]Long query time in PHP-MYSQL SELECT

我有一個PHP腳本,該腳本使用mysqli方法將查詢發送到Amazon RDS實例。 我注意到以下代碼需要大約一分鍾的時間來執行。 我想看看它掛在哪里。

該表非常大-超過3000萬行。 根據phpMyAdmin大約為8GB。 它運行在db.r3.large RDS實例上,該實例位於與Web服務器相同的可用區域和可用區域中。 我認為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進行故障排除。

由於通配符和LIKE比較,您的查詢未使用索引,因此運行了很長時間。

LIKE "%$query%"

在此處閱讀更多信息: http : //dev.mysql.com/doc/refman/5.6/en/index-btree-hash.html

如果可以接受,您可以將查詢更改為

LIKE "$query%"

盡管這將產生不同的結果,但它將(至少應該如此)創建一個更快的查詢。

通配符遠非理想!

您不能在SQL中使用LIKE "%...%"查詢並期望從中獲得良好的性能。 這樣的領先通配符搜索意味着數據庫將必須掃描表中的每個記錄以找到匹配項。 如果有很多匹配項,則最終還必須使用交換空間來存儲查詢結果。 永遠不會很快。 即使在中等大小的數據庫以及像您這樣的大型數據庫上,它可能也太慢了,它將非常痛苦。

您需要一種不同的方法。

有多種方法可以解決此問題,這取決於您要執行的操作。 如果要在字符串中查找關鍵字,則可以考慮將所有單詞拉出到單獨的表中各自的記錄中並進行搜索。 您最終將獲得有效的標簽系統。

但是通常,這樣的搜索需要的功能更多。 最好的解決方案通常是切換到SphinxLucene之類的專用數據索引工具。 這兩款產品相互運作方式略有不同,但它們有效地做同樣的工作:他們做了深刻的運行通過你的數據庫,並產生可以抵抗比什么數據庫可以提供多少更快的運行搜索的一個綜合指標。

它們的設置和配置可能很復雜,但是如果您想要那種靈活的搜索而又不存在LIKE查詢的性能問題,那么它們實際上是唯一的選擇。

如果使用LIKE "%..%" ,則每次運行查詢時,它將對所有3000萬行進行完全比較。 只有LIKE "...%"可以被緩存/索引。

如果您想在其中保留LIKE "%..%" ,我認為您無法加快查詢速度,但是,我有一些建議:

  • 使用WHERE last_name = :query 您確定要輸入與Alex和Alexander匹配的Alex嗎?
  • 制作自己的索引。 創建一個包含最常用的姓氏和/或其中一部分及其ID的表。 當用戶必須等待一分鍾時,不必每次都讀取3000萬行的值,而是創建一個在后台運行偶數小時的腳本,該腳本將構建一個包含30.000行的表,您可以在其中使用簡單的WHERE field = :query ,可以將其編入索引,並且速度更快。 - 我猜。
  • 讀取數十個數據需要花費時間。 確保您的表沒有100個不需要使用的列,或者不使用SELECT *

請不要使用->query("...$query...") PHP的MySQLi API具有綁定值的功能: bind_param

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM