1

我是一名自学成才的 AS3/Flex/AIR 开发人员,我已经构建了一个在 AIR 上运行的触摸屏信息亭系统,并通过在线 Flex 应用程序进行远程内容管理。

这是我第一次做服务器端的东西,所以如果需要,请随时纠正我的问题。

AIR 应用程序和 Flex 应用程序都连接到 mysql 数据库,以便使用 php 脚本和 Zend 框架进行简单的 CRUD 操作。信息亭每 30 秒调用一次服务器进行更新。

所有这些简单的服务器端 php 脚本都是由 Flash Builder 的数据向导自动生成的。我做了简单的调整(gateway.php、amf_config.ini、mysqli 连接参数)并将所有内容部署到客户端的服务器上。这是一个共享服务器类型。

现在,系统工作。但它工作缓慢。每个创建/读取/更新/删除操作都有效,但我认为它应该快得多。此外,这些操作给服务器的 cpu 带来了很大的负载。根据托管人员的说法,该系统打开的 php-cgi 进程占用了服务器 CPU 功率的 40%,这样做会减慢自身和该服务器上托管的其他站点的速度。

我的问题是:

首先,是不是一开始就有问题,或者这个性能是从 Zend 框架中扩展出来的?Flash Builder 编写的自动生成的脚本是否写得不好并且可以优化?这种系统可以保留在共享托管服务器上吗?我们是否应该迁移到 VPS 服务器以获得更好的性能?如果我使用 phpmyadmin 在 mysql 数据库上创建的表没有经过优化构建,是否会对性能产生这种影响?

我不知道php或mysql。任何形式的帮助都会非常感激。

萨尔

这是由 Flash Builder 编写的脚本: 我没有添加任何内容 - 只是更改了连接参数。

<?php

class KiosksService {

   var $username = "--------";
   var $password = "--------";
   var $server = "--------";
   var $port = "3306";
   var $databasename = "--------";
   var $tablename = "kiosks";

   var $connection;

   /**
    * The constructor initializes the connection to database. Everytime a request is 
    * received by Zend AMF, an instance of the service class is created and then the
    * requested method is invoked.
    */
   public function __construct() {
        $this->connection = mysqli_connect(
                          $this->server,  
                          $this->username,  
                          $this->password, 
                          $this->databasename,
                          $this->port
                       );

      $this->throwExceptionOnError($this->connection);
   }

   /**
    * Returns all the rows from the table.
    *
    * Add authroization or any logical checks for secure access to your data 
    *
    * @return array
    */
   public function getAllKiosks() {

      $stmt = mysqli_prepare($this->connection, "SELECT * FROM $this->tablename");      
      $this->throwExceptionOnError();

      mysqli_stmt_execute($stmt);
      $this->throwExceptionOnError();

      $rows = array();

      mysqli_stmt_bind_result($stmt, $row->KioskID, $row->Station, $row->Branch, $row->Chain, $row->Pingdate, $row->Layout, $row->Online, $row->Clips, $row->Extra);

       while (mysqli_stmt_fetch($stmt)) {
         $row->Pingdate = new DateTime($row->Pingdate);
         $rows[] = $row;
         $row = new stdClass();
         mysqli_stmt_bind_result($stmt, $row->KioskID, $row->Station, $row->Branch, $row->Chain, $row->Pingdate, $row->Layout, $row->Online, $row->Clips, $row->Extra);
       }

      mysqli_stmt_free_result($stmt);
       mysqli_close($this->connection);

       return $rows;
   }

   /**
    * Returns the item corresponding to the value specified for the primary key.
    *
    * Add authorization or any logical checks for secure access to your data 
    *
    * 
    * @return stdClass
    */
   public function getKiosksByID($itemID) {

      $stmt = mysqli_prepare($this->connection, "SELECT * FROM $this->tablename where KioskID=?");
      $this->throwExceptionOnError();

      mysqli_stmt_bind_param($stmt, 'i', $itemID);      
      $this->throwExceptionOnError();

      mysqli_stmt_execute($stmt);
      $this->throwExceptionOnError();

      mysqli_stmt_bind_result($stmt, $row->KioskID, $row->Station, $row->Branch, $row->Chain, $row->Pingdate, $row->Layout, $row->Online, $row->Clips, $row->Extra);

      if(mysqli_stmt_fetch($stmt)) {
         $row->Pingdate = new DateTime($row->Pingdate);
         return $row;
      } else {
         return null;
      }
   }

   /**
    * Returns the item corresponding to the value specified for the primary key.
    *
    * Add authorization or any logical checks for secure access to your data 
    *
    * 
    * @return stdClass
    */
   public function createKiosks($item) {

      $stmt = mysqli_prepare($this->connection, "INSERT INTO $this->tablename (Station, Branch, Chain, Pingdate, Layout, Online, Clips, Extra) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
      $this->throwExceptionOnError();

      mysqli_stmt_bind_param($stmt, 'sssssisi', $item->Station, $item->Branch, $item->Chain, $item->Pingdate->toString('YYYY-MM-dd HH:mm:ss'), $item->Layout, $item->Online, $item->Clips, $item->Extra);
      $this->throwExceptionOnError();

      mysqli_stmt_execute($stmt);      
      $this->throwExceptionOnError();

      $autoid = mysqli_stmt_insert_id($stmt);

      mysqli_stmt_free_result($stmt);      
      mysqli_close($this->connection);

      return $autoid;
   }

   /**
    * Updates the passed item in the table.
    *
    * Add authorization or any logical checks for secure access to your data 
    *
    * @param stdClass $item
    * @return void
    */
   public function updateKiosks($item) {

      $stmt = mysqli_prepare($this->connection, "UPDATE $this->tablename SET Station=?, Branch=?, Chain=?, Pingdate=?, Layout=?, Online=?, Clips=?, Extra=? WHERE KioskID=?");      
      $this->throwExceptionOnError();

      mysqli_stmt_bind_param($stmt, 'sssssisii', $item->Station, $item->Branch, $item->Chain, $item->Pingdate->toString('YYYY-MM-dd HH:mm:ss'), $item->Layout, $item->Online, $item->Clips, $item->Extra, $item->KioskID);      
      $this->throwExceptionOnError();

      mysqli_stmt_execute($stmt);      
      $this->throwExceptionOnError();

      mysqli_stmt_free_result($stmt);      
      mysqli_close($this->connection);
   }

   /**
    * Deletes the item corresponding to the passed primary key value from 
    * the table.
    *
    * Add authorization or any logical checks for secure access to your data 
    *
    * 
    * @return void
    */
   public function deleteKiosks($itemID) {

      $stmt = mysqli_prepare($this->connection, "DELETE FROM $this->tablename WHERE KioskID = ?");
      $this->throwExceptionOnError();

      mysqli_stmt_bind_param($stmt, 'i', $itemID);
      mysqli_stmt_execute($stmt);
      $this->throwExceptionOnError();

      mysqli_stmt_free_result($stmt);      
      mysqli_close($this->connection);
   }


   /**
    * Returns the number of rows in the table.
    *
    * Add authorization or any logical checks for secure access to your data 
    *
    * 
    */
   public function count() {
      $stmt = mysqli_prepare($this->connection, "SELECT COUNT(*) AS COUNT FROM $this->tablename");
      $this->throwExceptionOnError();

      mysqli_stmt_execute($stmt);
      $this->throwExceptionOnError();

      mysqli_stmt_bind_result($stmt, $rec_count);
      $this->throwExceptionOnError();

      mysqli_stmt_fetch($stmt);
      $this->throwExceptionOnError();

      mysqli_stmt_free_result($stmt);
      mysqli_close($this->connection);

      return $rec_count;
   }


   /**
    * Returns $numItems rows starting from the $startIndex row from the 
    * table.
    *
    * Add authorization or any logical checks for secure access to your data 
    *
    * 
    * 
    * @return array
    */
   public function getKiosks_paged($startIndex, $numItems) {

      $stmt = mysqli_prepare($this->connection, "SELECT * FROM $this->tablename LIMIT ?, ?");
      $this->throwExceptionOnError();

      mysqli_stmt_bind_param($stmt, 'ii', $startIndex, $numItems);
      mysqli_stmt_execute($stmt);
      $this->throwExceptionOnError();

      $rows = array();

      mysqli_stmt_bind_result($stmt, $row->KioskID, $row->Station, $row->Branch, $row->Chain, $row->Pingdate, $row->Layout, $row->Online, $row->Clips, $row->Extra);

       while (mysqli_stmt_fetch($stmt)) {
         $row->Pingdate = new DateTime($row->Pingdate);
         $rows[] = $row;
         $row = new stdClass();
         mysqli_stmt_bind_result($stmt, $row->KioskID, $row->Station, $row->Branch, $row->Chain, $row->Pingdate, $row->Layout, $row->Online, $row->Clips, $row->Extra);
       }

      mysqli_stmt_free_result($stmt);      
      mysqli_close($this->connection);

      return $rows;
   }


   /**
    * Utility function to throw an exception if an error occurs 
    * while running a mysql command.
    */
   private function throwExceptionOnError($link = null) {
      if($link == null) {
         $link = $this->connection;
      }
      if(mysqli_error($link)) {
         $msg = mysqli_errno($link) . ": " . mysqli_error($link);
         throw new Exception('MySQL Error - '. $msg);
      }      
   }
}

?>
4

2 回答 2

0

虽然 Zend 框架的性能可能有点问题,但您的示例中没有 zend 框架代码

该系统打开 6 个 php-cgi 进程

对于每个操作?这似乎不太可能。如果您提供显示典型事务的访问日志样本以及他们提供的支持此断言的证据,将会很有帮助。

如果您对性能(或您的服务器机房有多热)有一点担心,那么通过 cgi 运行 php 是一个非常糟糕的主意。使用 mod_php 或 php-fpm 甚至 php via fcgi 以及操作码缓存将减少 75% 以上的执行时间。

查看代码,这里没有什么明显不好的地方——除了 getKiosks_paged——在没有明确的 ORDER BY 的情况下进行行范围选择是非常草率的。

每个创建/读取/更新/删除操作都有效,但我认为它应该快得多

它有多快?网络服务器上的请求多长时间,它执行什么查询?他们需要多长时间?你的数据库的结构是什么?您的查询的解释计划是什么样的?

于 2012-12-28T14:59:11.613 回答
0

我无法评论 Zend 框架,因为我从未使用过它。

CGI 总是比 Fast CGI 慢,或者更好的是 mod_php 或类似的东西。当您使用 CGI 时,每次启动解释器并在脚本完成后,所有内容都会被拆除。

当您改用 Fast CGI 或 PHP 模块时,Web 服务器模块可以跨调用维护一些状态,例如数据库连接。

于 2012-12-28T14:59:57.600 回答