2013-08-16 137 views
1

我使用Zend框架和頁面加載在生產服務器上比在開發一個慢得多的一個站點工作的14倍。經過一些挖掘和分析(使用xdebug)之後,我發現PDOStatement-> execute調用在生產服務器上運行11 134毫秒,在開發服務器上運行780毫秒。PDOStatement->執行較慢的生產服務器上比開發服務器

數據庫是兩臺服務器上是相同的,MySQL的版本是兩個服務器(32年5月5日)和MySQL配置在相同的兩個服務器上相同的(下降到在my.cnf的線)。兩臺服務器也都運行Ubuntu 12.04.2 LTS,儘管開發服務器與生產服務器相比具有額外的軟件。我能想到的唯一區別是dev服務器在SSD上運行,而生產服務器運行RAID 0中的兩個常規SATA驅動器。然而,在phpMyAdmin中運行查詢大概是同一時間(0.0003-0.0005秒,儘管我不信任phpMyAdmin執行時間報告)。


這裏是我運行的查詢:

$query = "SET @rank = 0"; 
$statement = $db->query($query); 

$query = "SET @previous_result = -1"; 
$statement = $db->query($query); 

$query = " 
    SELECT 
     @group_id := IFNULL(g.id, -1) 
    FROM 
     `branch_statistics` bs 
    JOIN 
     branch_to_wave btw ON bs.branch_to_wave_id = btw.id 
    JOIN 
     branch_to_group btg ON bs.branch_id = btg.branch_id 
    JOIN 
     `group` g ON btg.group_id = g.id 
    WHERE 
     btw.wave_id = $wave_id AND bs.branch_id = $branch_id"; 
$statement = $db->query($query); 

$query = "DROP TABLE IF EXISTS group_members"; 
$statement = $db->query($query); 

$query = "CREATE TEMPORARY TABLE group_members (id INT PRIMARY KEY)"; 
$statement = $db->query($query); 

$query = "DROP TABLE IF EXISTS group_members2"; 
$statement = $db->query($query); 

$query = "CREATE TEMPORARY TABLE group_members2 (id INT PRIMARY KEY)"; 
$statement = $db->query($query); 

$query = " 
    INSERT INTO 
     group_members 
     SELECT 
      btw.id 
     FROM 
      branch_to_wave btw 
     JOIN 
      branch_to_group btg ON btw.branch_id = btg.branch_id 
     WHERE 
      btw.wave_id = $wave_id AND 
      btg.group_id = @group_id 
     GROUP BY 
      btw.id"; 
$statement = $db->query($query); 

$query = "INSERT INTO group_members2 SELECT id FROM group_members"; 
$statement = $db->query($query); 

$query = " 
    SELECT @number_of_results := 
     COUNT(result) 
    FROM 
     (
     SELECT 
      ROUND(points/maximum_points, 4) as result 
     FROM 
      `branch_statistics` bs 
     JOIN 
      group_members2 gm2 ON gm2.id = bs.branch_to_wave_id 
     GROUP BY 
      result 
     ) results 
"; 
$statement = $db->query($query); 

$query = " 
    EXPLAIN SELECT 
     *, 
     @number_of_results as number_of_results 
    FROM 
     (
      SELECT 
       *, 
       IF(@previous_result != result, @rank := @rank + 1, @rank) as rank, 
       @previous_result := result 
      FROM 
       (
       SELECT 
        bs.branch_id, 
        ROUND(points/maximum_points, 4) as result, 
        (
         SELECT 
          AVG(ROUND(points/maximum_points, 4)) as average 
         FROM 
          `branch_statistics` bs 
         JOIN 
          group_members2 gm2 ON gm2.id = bs.branch_to_wave_id 
        ) as average 
       FROM 
        `branch_statistics` bs 
       JOIN 
        group_members gm ON gm.id = bs.branch_to_wave_id 
       GROUP BY 
        bs.branch_id 
       ORDER BY 
        result DESC 
       ) complete 
     ) results 
    WHERE branch_id = $branch_id 
"; 
$statement = $db->query($query); 

$statement->setFetchMode(Zend_Db::FETCH_NUM); 
$results = $statement->fetchAll(); 

我不知道,如果服務器規格是相關的,但在這裏,他們在任何情況下:

生產服務器:

英特爾(R)核心(TM)2雙核CPU E7500 @ 2.93GHz的與3.4G b RAM

開發服務器(運行在以下硬件的虛擬機,與其他的虛擬機5-6):

AMD FX(TM)-8120八核心處理器與RAM的3Gb


所以我的問題是這樣的:我怎麼能找出是什麼原因造成這種差異?


編輯#1(2013年8月16日@ 11:23):對於那些不熟悉與Zend框架,這裏是調用堆棧導致PDOStatement->執行:

  1. $ db-> query($ query);
  2. Zend_Db_Adapter_Pdo_Abstract->查詢
  3. Zend_Db_Statement->執行
  4. Zend_Db_Statement_Pdo->執行
  5. PDOStatement->執行

編輯#2(2013年8月16日@ 13 :09):這裏是兩臺機器的性能分析結果。

Status        Duration DEV Duration PROD 
starting       0.000032  0.000010 
Waiting for query cache lock  0.000010  0.000006 
checking query cache for query  0.000183  0.000074 
checking permissions    0.000010  0.000007 
checking permissions    0.000009  0.000006 
checking permissions    0.000009  0.000006 
checking permissions    0.000011  0.000007 
Opening tables      0.000030  0.000017 
System lock       0.000140  0.000063 
optimizing       0.000016  0.000010 
statistics       0.000035  0.000016 
preparing       0.000020  0.000011 
Creating tmp table     0.000028  0.000015 
executing       0.000009  0.000006 
Copying to tmp table    0.000424  0.000133 
Sorting result      0.000039  0.000017 
Sending data      0.000015  0.000008 
optimizing       0.000014  0.000009 
statistics       0.000022  0.000012 
preparing       0.000019  0.000010 
executing       0.000011  0.000007 
Sending data      0.000171  0.000110 
optimizing       0.000006  0.000007 
statistics       0.000006  0.000008 
preparing       0.000006  0.000007 
executing       0.000004  0.000006 
Sending data      0.000042  0.000035 
removing tmp table     0.000007  0.000009 
Sending data      0.000006  0.000008 
init        0.000011  0.000013 
optimizing       0.000005  0.000008 
statistics       0.000006  0.000008 
preparing       0.000006  0.000009 
executing       0.000004  0.000006 
Sending data      0.000016  0.000019 
end         0.000005  0.000007 
query end       0.000005  0.000007 
closing tables      0.000004  0.000006 
removing tmp table     0.000005  0.000007 
closing tables      0.000004  0.000006 
removing tmp table     0.000006  0.000007 
closing tables      0.000006  0.000008 
freeing items      0.000013  0.000275 
logging slow query     0.000004  0.000007 
cleaning up       0.000006  0.000007 

我還測試mysqlslap,發現一些非常有趣的結果,隨後(時間是平均查詢時間)。您可以看到,儘管同時進行多個同時查詢確實會增加平均查詢時間,但與開發服務器相比,同一查詢在生產服務器上的速度仍然低24倍。

我不太明白如何在phpMyAdmin中運行查詢可以花費0.0005秒,而使用mysqlslap的相同查詢需要0.299秒,但我懷疑存在我的問題的核心。

Mysqlslap settings      Dev   Prod 
iterations = 10, concurrency = 50  1.253  14.129 
iterations = 10, concurrency = 25  0.513  7.153 
iterations = 10, concurrency = 10  0.141  3.133 
iterations = 10, concurrency = 1  0.014  0.299 
+0

你有沒有看每條語句督促服務器上執行計劃相比,開發服務器? mySQL中的執行計劃可能會顯示您缺少索引,生產中的數據與dev不同,或者使用了錯誤的索引導致延遲。但直到您將其縮小到個人陳述的範圍內時,這裏的任何人都難以排除故障。 – xQbert

+0

性能降低很容易從這裏猜到,但大多數情況下,你必須看幾個關鍵的東西。假設你的開發環境和產品環境中有相同的模式,請查看數據大小。在你的工具上使用mysqlslap類似工具dev機器來檢查重負載下的性能,因爲dev env通常不會像您的prod機器那樣做很多工作。 – WordsWorth

+0

您是否嘗試過沒有PDO的相同查詢? –

回答

3

我終於明白了今天!問題在於臨時表不是在生產服務器的內存中創建的。我不知道爲什麼,因爲配置文件明確說明它應該,但我通過將ENGINE = MEMORY添加到所有CREATE TEMPORARY TABLE調用解決了該問題。

例如爲:

CREATE TEMPORARY TABLE group_members (id INT PRIMARY KEY) ENGINE = MEMORY 
相關問題