请帮助确定我的应用程序中的MySQL性能瓶颈

时间:2010-10-19 05:41:44

标签: php mysql facebook performance

我有一个我用PHP / MYSQL和FBJS / AJAX编写的Facebook应用程序。该应用程序是Rails Across Europe,可以在http://apps.facebook.com/rails_across_europe找到(请注意,它确实需要访问您的FB数据)。如果您想查看应用程序操作的截屏视频,可以在http://screenr.com/TZRhttp://screenr.com/sZR(每个截屏视频约3分钟)进行操作。

问题是对用户输入的响应非常慢。我不确定是什么原因导致这个性能瓶颈。我对性能优化没有任何经验,这就是为什么我会请求你的帮助。我认为瓶颈可能是以下任何一个方面:

  • MySQL的
  • AJAX
  • 网络服务器

关于我的网络托管,我使用的是A2 Hosting共享托管帐户。我不确定这种类型的Web主机是否能够处理我的应用程序所需的密集型数据库和用户活动,但这是我能负担得起的。如果这可能是我的性能问题的根源,请告诉我。

为了帮助确定性能问题的根源,我提供了一些源代码。第一个是SQL查询,第二个是AJAX调用。

列车运动似乎是最慢的运行,所以我将以此为例。我意识到这是一个非常长的代码示例,但除非我提交整个上下文供您审阅,否则我不知道有谁可以帮助我。这是PHP / MYSQL代码:

MoveTrain.php

  public function moveTrain($destCityId) {
    require_once 'Train.php';
    $trainModel = new Train();

    require_once 'Route.php';
    $routeModel = new Route();

    $userNamespace = new Zend_Session_Namespace('User');
    $gamePlayerId = $userNamespace->gamePlayerId;

    $trainData = $trainModel->getTrain($gamePlayerId);

    $originCityId = $trainData['origin_city_id'];
    $destChanged = false;
    if ( $destCityId != $trainData['dest_city_id'] ) {
        $originCityId = $trainData['dest_city_id'];
        $destChanged = true;
    }
    $routeResp = $routeModel->getPlayerRouteIdByCityIds($gamePlayerId, $originCityId, $destCityId);
    $routeId = $routeResp['route_id'];
    $trainRow = array();
    // if route is invalid OR if destination city has not changed and train has arrived,
    // bypass train movement
    if($routeResp['error_msg'] == 'SUCCESS' || ($routeResp['error_msg'] == 'ROUTE_NOT_OWNED' && !$destChanged)) {
      if((!$destChanged && $trainData['status'] == 'ENROUTE') ||
         ($destChanged && $trainData['status'] == 'ARRIVED')) {
        $routeData = $routeModel->getRouteByCityIds($originCityId, $destCityId);
        $unitsToDestination = 0;
        $trainRow['direction'] = $routeModel->getRouteTravelDirection($originCityId, $destCityId); //+
        // if traveling to a new city destination and traveling negative then train track unit
        // is equal to route track unit count (because train is at the end of a new route)
        switch ($trainRow['direction']) {
            case '+':
                if($destChanged && $trainData['status'] == 'ARRIVED') {
                  $trainData['track_unit'] = 0;
                }
                $unitsToDestination = $routeData['track_unit_count'] - $trainData['track_unit'];
                break;
            case '-':
                if($destChanged && $trainData['status'] == 'ARRIVED') {
                  $trainData['track_unit'] = $routeData['track_unit_count'];
                }
                $unitsToDestination = $trainData['track_unit'];
                break;
            default:
                break;
        }
        // 2. Move the train
        $unitsToDestination = $unitsToDestination - $trainData['track_units_remaining'];
        $trackUnitsRemaining = 0;
        $trainArrived = false;

        // Note that I changed from < to <=
        if ( $unitsToDestination <= 0) {
            // Went too far or arrived.
            $trackUnitsRemaining = abs($unitsToDestination);
            $trackUnit = $routeData['track_unit_count'];
            if($trainRow['direction'] == '-') {
              $trackUnit = 0;
            }
            $trainArrived = true;
        } else {
            // Did not reach destination
            $trackUnitsRemaining = 0;
            switch ( $trainRow['direction'] ) {
                    case '+':
                            $trackUnit = $routeData['track_unit_count'] - $unitsToDestination;
                            break;
                    case '-':
                            $trackUnit = $unitsToDestination;
                            break;
                    default:
                            break;
            }
        }
        // 3. Save changes carefully.
        $trainRow['route_id'] = $routeId;
        $trainRow['origin_city_id'] = $originCityId;
        $trainRow['dest_city_id'] = $destCityId;
        $trainRow['track_unit'] = $trackUnit; //5
        $trainRow['track_units_remaining'] = $trackUnitsRemaining; //2
        // $trainArrived = ($trackUnit == 0 || $trackUnit == $routeData['track_unit_count']);
        $trainRow['status'] = ($trainArrived) ? 'ARRIVED' : 'ENROUTE';
        $trainRow['date_last_used'] = date('Y-m-d H:i:s');

        //$trainId = $trainModel->getTrainId($gamePlayerId);
        $where = $trainModel->getAdapter()->quoteInto('id = ?', $trainData['id']);
        $trainModel->update($trainRow, $where);
      } else {
        $trainRow = $trainData;
      }
    }
    return $trainRow;
  }

Train.php:
  public function getTrain($gamePlayerId) {
    $sql = $this->getAdapter()->quoteInto("SELECT gp.player_number, t.* FROM train t, game_player gp WHERE t.`game_player_id` = ?", $gamePlayerId)
         . ' AND gp.id = t.game_player_id;';
    $stmt = $this->getAdapter()->query($sql);
    $train = $stmt->fetchAll();
    return $train[0];
  }

Route.php:
  public function getPlayerRouteIdByCityIds($gamePlayerId, $cityId1, $cityId2) {
    $resp = array('route_id' => null, 'error_msg' => 'INVALID_ROUTE');

    $where = $this->getAdapter()->quoteInto('(city_id_1 = ?', $cityId1)
           . $this->getAdapter()->quoteInto(' AND city_id_2 = ?)', $cityId2)
           . $this->getAdapter()->quoteInto(' OR (city_id_1 = ?', $cityId2)
           . $this->getAdapter()->quoteInto(' AND city_id_2 = ?)', $cityId1);

    $select = $this->select()->where($where);
    $row = $this->fetchRow($select);

    if($row) {
      require_once 'PlayerRoute.php';
      $playerRouteModel = new PlayerRoute();
      if($playerRouteModel->isRouteOwned($row->id, $gamePlayerId)) {
        $resp['route_id'] = $row->id;
        $resp['error_msg'] = 'SUCCESS';
        return $resp;
      }
      $resp['error_msg'] = 'ROUTE_NOT_OWNED';
    }
    return $resp;

  }

  public function getRouteByCityIds($cityId1, $cityId2) {
    $db = $this->getAdapter();
    $sql =                'SELECT * FROM route AS r'
         . $db->quoteInto(' WHERE (r.city_id_1 = ?', $cityId1)
         . $db->quoteInto(' AND r.city_id_2 = ?)', $cityId2)
         . $db->quoteInto(' OR (r.city_id_1 = ?', $cityId2)
         . $db->quoteInto(' AND r.city_id_2 = ?);', $cityId1);

    $stmt = $db->query($sql);

    $routeRow = array();
    foreach($stmt as $row) {
      $routeRow = $row;
    }
    if(count($routeRow) == 0) { return false; }
    $sql = $db->quoteInto('SELECT track_unit_count FROM route_count WHERE id = ?', $routeRow['id']);
    $stmt = $db->query($sql);
    foreach($stmt as $row) {
      $routeRow['track_unit_count'] = $row['track_unit_count'];
    }
    return $routeRow;
  }

  public function getRouteTravelDirection($startCityId, $endCityId) {
    $routeData = $this->getRouteByCityIds($startCityId, $endCityId);
    return ($routeData['city_id_1'] == $startCityId) ? '+' : '-';
  }


PlayerRoute.php
  public function isRouteOwned($routeId, $gamePlayerId) {
    $where = $this->_db->quoteInto('route_id = ?', $routeId)
           . $this->_db->quoteInto(' AND game_player_id = ?', $gamePlayerId);

    $select = $this->select()->where($where);
    $row = $this->fetchRow($select);
    return (!$row) ? false : true;
  }

我决定不提交FBJS / AJAX代码示例。也许我会将其作为另一个问题提交。感谢任何可以帮助我的人。

1 个答案:

答案 0 :(得分:0)

修改my.conf以记录长查询并将时间设置得相当高(可能是5秒)。如果性能问题是一个mysql查询,你会在日志中看到它。