我正在运行一个大型PHP脚本来获取适用于搜索查询等的数据库信息。问题是页面的加载时间是几秒钟(本地),而远程数据库的加载时间是一分钟。
在优化方面,我不是最好的,但我知道查询中的星号,但在这种情况下我需要它,因为我正在使用表中的所有字段。
请记住,它从中获取数据的表总共超过800k行(没有显示800k行,如我在显示它的代码WHERE = something
中所示)
<?php
$getPage = $mysqli->real_escape_string(@$_GET["page"]);
$getSearch = $mysqli->real_escape_string(@$_GET["search"]);
$getUser = $mysqli->real_escape_string(@$_GET["user"]);
if(isset($getPage)) { $page = $getPage; } else { $page = 1; };
$start_from = ($page-1) * 12;
$order = $mysqli->real_escape_string(@$_GET["ord"]);
$order_query = "item_name ASC";
if($start_from >= 0) {
if($getSearch)
{
if($order)
{
if($order == 1)
{
$order_query = "item_name ASC";
}
if($order == 2)
{
$order_query = "item_name DESC";
}
if($order == 3)
{
$order_query = "item_id ASC";
}
if($order == 4)
{
$order_query = "item_id DESC";
}
$shop = $mysqli->query("SELECT * FROM store_inventory WHERE (item_name LIKE '%".$getSearch."%' OR item_type LIKE '%".$getSearch."%' OR item_quality LIKE '%".$getSearch."%') AND steamid = '".$getUser."' GROUP BY item_id ORDER BY ".$order_query." LIMIT $start_from, 28");
}
else
{
$shop = $mysqli->query("SELECT * FROM store_inventory WHERE (item_name LIKE '%".$getSearch."%' OR item_type LIKE '%".$getSearch."%' OR item_quality LIKE '%".$getSearch."%') AND steamid = '".$getUser."' GROUP BY item_id ORDER BY item_name ASC LIMIT $start_from, 28");
}
}
else
{
if($order)
{
if($order == 1)
{
$order_query = "item_name ASC";
}
if($order == 2)
{
$order_query = "item_name DESC";
}
if($order == 3)
{
$order_query = "item_id ASC";
}
if($order == 4)
{
$order_query = "item_id DESC";
}
$shop = $mysqli->query("SELECT * FROM store_inventory WHERE steamid = '".$getUser."' GROUP BY item_id ORDER BY ".$order_query." LIMIT $start_from, 28");
}
else
{
$shop = $mysqli->query("SELECT * FROM store_inventory WHERE steamid = '".$getUser."' GROUP BY item_id ORDER BY item_name ASC LIMIT $start_from, 28");
}
}
} else {
$start_from = 0;
if($getSearch)
{
if($order)
{
if($order == 1)
{
$order_query = "item_name ASC";
}
if($order == 2)
{
$order_query = "item_name DESC";
}
if($order == 3)
{
$order_query = "item_id ASC";
}
if($order == 4)
{
$order_query = "item_id DESC";
}
$shop = $mysqli->query("SELECT * FROM store_inventory WHERE (item_name LIKE '%".$getSearch."%' OR item_type LIKE '%".$getSearch."%' OR item_quality LIKE '%".$getSearch."%') AND steamid = '".$getUser."' GROUP BY item_id ORDER BY ".$order_query." LIMIT $start_from, 28");
}
else
{
$shop = $mysqli->query("SELECT * FROM store_inventory WHERE (item_name LIKE '%".$getSearch."%' OR item_type LIKE '%".$getSearch."%' OR item_quality LIKE '%".$getSearch."%') AND steamid = '".$getUser."' GROUP BY item_id ORDER BY item_name ASC LIMIT $start_from, 28");
}
}
else
{
if($order)
{
if($order == 1)
{
$order_query = "item_name ASC";
}
if($order == 2)
{
$order_query = "item_name DESC";
}
if($order == 3)
{
$order_query = "item_id ASC";
}
if($order == 4)
{
$order_query = "item_id DESC";
}
$shop = $mysqli->query("SELECT * FROM store_inventory WHERE steamid = '".$getUser."' GROUP BY item_id ORDER BY ".$order_query." LIMIT $start_from, 28");
}
else
{
$shop = $mysqli->query("SELECT * FROM store_inventory WHERE steamid = '".$getUser."' GROUP BY item_id ORDER BY item_name ASC LIMIT $start_from, 28");
}
}
}
$countarticles = $mysqli->query("SELECT COUNT(item_id) FROM store_inventory");
$row = $countarticles->fetch_row();
$total_records = $row[0];
$total_pages = ceil($total_records / 28);
$Pages[] = "";
for ($i = 1; $i <= $total_pages; $i++) {
$Pages[] = "<li><a href='?page=".$i."'>".$i."</a></li>";
}
while($fetch_market = $shop->fetch_array())
{
$iInv[] = $fetch_market;
}
如何显着减少脚本/页面的加载时间?
答案 0 :(得分:1)
这是您的选择查询。
SELECT *
FROM store_inventory
WHERE ( item_name LIKE '%".$getSearch."%'
OR item_type LIKE '%".$getSearch."%'
OR item_quality LIKE '%".$getSearch."%'
)
AND steamid = '".$getUser."'
GROUP BY item_id ORDER BY ".$order_query."
LIMIT $start_from, 28
相对而言,您编写此查询的方式保证非常慢。
为什么?
首先,您正在使用WHERE column LIKE '%value%'
。这种过滤器表达式不可能被索引加速。为什么不?因为它必须查看列中的每个值以查看它是否与您的表达式匹配。另一方面,WHERE column LIKE 'value%'
没有前导%
,可以利用索引。您拥有它的方式需要全表扫描才能执行过滤。
其次,您使用了三个OR
个表达式,每个表达式都有效果不佳的LIKE
过滤器。这会将您的一张桌子扫描成三张,将所用时间增加三倍。
第三,你在这里滥用GROUP BY
。 MySQL可以让你在这里找到各种奇怪的东西。阅读本文:https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html我会就如何解决此问题提出建议,但我无法猜测你想要做什么。
第四,您正在使用臭名昭着的SELECT * ... ORDER BY x LIMIT y
性能反模式。这样排除了一大堆乱七八糟的行,只是为了丢弃其中的几行。
你能做些什么?首先,确保您在steamid
列上有索引。如果它具有合理的选择性,那么通过减少需要扫描的行数会有很大帮助。
其次,尝试用
上的复合索引替换steamid
索引
steamid, item_name, item_type, item_quality
可能(或可能不会)使您的LIKE
扫描效率更高。
第三,找出你用GROUP BY
实际想要完成的事情并尝试正确地做到这一点。
第四,尽量减轻ORDER BY
的负担。这样的事情可能有所帮助。
SELECT * FROM store_inventory
WHERE id IN (SELECT id
FROM store_inventory
WHERE ( this
OR that
OR the_other_thing
)
AND steamid = something
ORDER BY some_column
LIMIT start, count
)
这使得它只需要对id进行排序。它更快。
第五,查看MySQL的FULLTEXT搜索选项。它可以用更高效的方式替换你的LIKE
系列操作。
答案 1 :(得分:0)
为什么要使用PHP 7? 根据[Anna Monus] [1]
,PHP 7比PHP 5.6快两倍为什么要使用预备声明? PHP7 + MySQLi提供更好的性能和安全性。但是,您的代码仍然容易受到SQL注入的攻击。请注意,准备好的语句可能很慢。 准备好的语句只有在您准备语句然后多次执行时才会变得更快。但是,因为您正在使用mysqli_real_escape_string,它会对数据库进行往返,通过替换所有使用单个预准备语句的那些往返使您的代码更快。
为什么要使用功能 函数使您的代码更短,更易于维护,并且在大多数情况下,执行速度更快。因为您不断重复您的代码。您可以使用功能缩短它。
我知道这已经够了,所以这是你的代码:
$getPage = $mysqli->real_escape_string(@$_GET["page"]);
$getSearch = $mysqli->real_escape_string(@$_GET["search"]);
$getUser = $mysqli->real_escape_string(@$_GET["user"]);
if(isset($getPage)) { $page = $getPage; } else { $page = 1; };
$start_from = ($page-1) * 12;
$order = $mysqli->real_escape_string(@$_GET["ord"]);
$order_query = "item_name ASC";
function order_item($order) {
if($order == 1) {
$order_query = "item_name ASC";
}
if($order == 2) {
$order_query = "item_name DESC";
}
if($order == 3) {
$order_query = "item_id ASC";
}
if($order == 4) {
$order_query = "item_id DESC";
}
return $order_query;
}
function shop_type($type, $orderBy) {
$getSearch = "%$getSearch%";
if ( $type = 'searched' ) {
$add = "AND (item_name LIKE ? OR item_type LIKE ? OR item_quality LIKE ?)";
} else {
$add = "";
}
$stmt = $con->prepare("SELECT * FROM store_inventory
WHERE steamid = ?
".$add."
GROUP BY item_id
ORDER BY ".$orderBy." ASC
LIMIT $start_from, 28");
$stmt->bind_param("is", $getUser, $getSearch);
$stmt->execute();
$result = $stmt->get_result();
if($result->num_rows === 0) exit('No rows');
while($row = $result->fetch_assoc()) {
$arr[] = $row;
}
return $arr;
}
function get_items() {
if($getSearch) {
if($order) {
order_item($order);
$shop = shop_type('searched',$order_query);
} else {
$shop = shop_type('searched','item_name');
}
} else {
if($order) {
order_item($order);
$shop = shop_type('unsearched',$order_query);
} else {
$shop = shop_type('unsearched','item_name');
}
}
}
if($start_from >= 0) {
get_items();
} else {
$start_from = 0;
get_items();
}
$countarticles = $mysqli->query("SELECT COUNT(item_id) FROM store_inventory");
$row = $countarticles->fetch_row();
$total_records = $row[0];
$total_pages = ceil($total_records / 28);
$Pages[] = "";
for ($i = 1; $i <= $total_pages; $i++) {
$Pages[] = "<li><a href='?page=".$i."'>".$i."</a></li>";
}
while($fetch_market = $shop->fetch_array())
{
$iInv[] = $fetch_market;
}
将函数放在单独的PHP文件中,并使用:
调用它require "filename.php";
希望这有帮助!