2011-06-22 119 views
15

我在PHP中使用PDO對象來運行MYSQL查詢,並且我一直在嘗試處理查詢以加速它。該查詢如下,在我的PHP文件中看到:

PDO比mysql查詢慢得多?

$query = 
"SELECT SQL_NO_CACHE f.position, s.item_id, s.item_type, s.title, s.caption, s.date 
FROM apiv2.search_all s 
INNER JOIN apiv2.tags t 
USING(item_id, item_type) 
LEFT JOIN apiv2.featured f 
ON t.item_id = f.item_id AND t.item_type = f.item_type AND f.feature_type = :id 
WHERE t.tag = 'FeaturedContent' 
ORDER BY position IS NULL, position ASC, date"; 

$mysql_vars[':id'] = $id; 
$stmt = $connection->prepare($query); 
$stmt->execute($vars); 
$data = $stmt->fetchAll(PDO::FETCH_ASSOC); 

此查詢運行顯著不同,這取決於我是否包含ORDER BY子句,但只能在MYSQL控制檯:

- MYSQL Console with ORDER BY: 1.07 sec 
    - starting 0.000141 
    - Opening tables 0.001416 
    - System lock 0.000003 
    - Table lock 0.000007 
    - init 0.000021 
    - checking permissions 0.000001 
    - checking permissions 0.000036 
    - optimizing 0.000027 
    - statistics 0.000027 
    - preparing 0.000015 
    - Creating tmp table 0.003440 
    - executing 0.000001 
    - Copying to tmp table 1.050029 
    - Sorting result 0.013097 
    - Sending data 0.000295 
    - end 0.000002 
    - removing tmp table 0.002045 
    - end 0.000003 
    - query end 0.000002 
    - freeing items 0.000331 
    - logging slow query 0.000002 
    - cleaning up 0.000007 
- MYSQL Console unordered output: .0053 sec 
    - starting 0.000076 
    - Opening tables 0.001506 
    - System lock 0.000002 
    - Table lock 0.000005 
    - init 0.000015 
    - checking permissions 0.000001 
    - checking permissions 0.000022 
    - optimizing 0.000012 
    - statistics 0.000021 
    - preparing 0.000011 
    - executing 0.000001 
    - Sending data 0.002895 
    - end 0.000002 
    - query end 0.000001 
    - freeing items 0.000078 
    - logging slow query 0.000000 
    - cleaning up 0.000002 
- PDO Prepared stmt ORDER BY: 1.18 sec 
    - 'Status' => 'starting', 'Duration' => '0.000147' 
    - 'Status' => 'Opening tables', 'Duration' => '0.000784' 
    - 'Status' => 'System lock', 'Duration' => '0.000004' 
    - 'Status' => 'Table lock', 'Duration' => '0.000007' 
    - 'Status' => 'init', 'Duration' => '0.000017' 
    - 'Status' => 'checking permissions', 'Duration' => '0.000002' 
    - 'Status' => 'checking permissions', 'Duration' => '0.000028' 
    - 'Status' => 'optimizing', 'Duration' => '0.000018' 
    - 'Status' => 'statistics', 'Duration' => '0.000026' 
    - 'Status' => 'preparing', 'Duration' => '0.000014' 
    - 'Status' => 'Creating tmp table', 'Duration' => '0.002112' 
    - 'Status' => 'executing', 'Duration' => '0.000001' 
    - 'Status' => 'Copying to tmp table', 'Duration' => '1.033056' 
    - 'Status' => 'Sorting result', 'Duration' => '0.013759' 
    - 'Status' => 'Sending data', 'Duration' => '0.073144' 
    - 'Status' => 'end', 'Duration' => '0.000003' 
    - 'Status' => 'removing tmp table', 'Duration' => '0.001999' 
    - 'Status' => 'end', 'Duration' => '0.000004' 
    - 'Status' => 'query end', 'Duration' => '0.000007' 
    - 'Status' => 'freeing items', 'Duration' => '0.000118' 
    - 'Status' => 'logging slow query', 'Duration' => '0.000001' 
    - 'Status' => 'cleaning up', 'Duration' => '0.000003' 
- PDO Prepared stmt unordered output: 1.06 sec 
    - 'Status' => 'starting', 'Duration' => '0.000074' 
    - 'Status' => 'Opening tables', 'Duration' => '0.001364' 
    - 'Status' => 'System lock', 'Duration' => '0.000004' 
    - 'Status' => 'Table lock', 'Duration' => '0.000007' 
    - 'Status' => 'init', 'Duration' => '0.000017' 
    - 'Status' => 'checking permissions', 'Duration' => '0.000001' 
    - 'Status' => 'checking permissions', 'Duration' => '0.000026' 
    - 'Status' => 'optimizing', 'Duration' => '0.000015' 
    - 'Status' => 'statistics', 'Duration' => '0.000027' 
    - 'Status' => 'preparing', 'Duration' => '0.000013' 
    - 'Status' => 'executing', 'Duration' => '0.000002' 
    - 'Status' => 'Sending data', 'Duration' => '1.048216' 
    - 'Status' => 'end', 'Duration' => '0.000003' 
    - 'Status' => 'query end', 'Duration' => '0.000001' 
    - 'Status' => 'freeing items', 'Duration' => '0.000122' 
    - 'Status' => 'logging slow query', 'Duration' => '0.000001' 
    - 'Status' => 'cleaning up', 'Duration' => '0.000003' 
- MYSQL functions from PHP unordered: 1.09 sec 
    - 'Status' => 'starting', 'Duration' => '0.000109' 
    - 'Status' => 'checking permissions', 'Duration' => '0.000002' 
    - 'Status' => 'checking permissions', 'Duration' => '0.000001' 
    - 'Status' => 'checking permissions', 'Duration' => '0.000004' 
    - 'Status' => 'Opening tables', 'Duration' => '0.002101' 
    - 'Status' => 'System lock', 'Duration' => '0.000004' 
    - 'Status' => 'Table lock', 'Duration' => '0.000009' 
    - 'Status' => 'init', 'Duration' => '0.000032' 
    - 'Status' => 'checking permissions', 'Duration' => '0.000003' 
    - 'Status' => 'checking permissions', 'Duration' => '0.000057' 
    - 'Status' => 'optimizing', 'Duration' => '0.000033' 
    - 'Status' => 'statistics', 'Duration' => '0.000065' 
    - 'Status' => 'preparing', 'Duration' => '0.000032' 
    - 'Status' => 'executing', 'Duration' => '0.000005' 
    - 'Status' => 'Sending data', 'Duration' => '1.000079' 
    - 'Status' => 'end', 'Duration' => '0.000005' 
    - 'Status' => 'query end', 'Duration' => '0.000002' 
    - 'Status' => 'freeing items', 'Duration' => '0.000300' 
    - 'Status' => 'logging slow query', 'Duration' => '0.000001' 
    - 'Status' => 'cleaning up', 'Duration' => '0.000007' 
- MYSQL functions from PHP w/ ORDER BY: 1.09 sec 
    - 'Status' => 'starting', 'Duration' => '0.000148' 
    - 'Status' => 'checking permissions', 'Duration' => '0.000001' 
    - 'Status' => 'checking permissions', 'Duration' => '0.000001' 
    - 'Status' => 'checking permissions', 'Duration' => '0.000001' 
    - 'Status' => 'Opening tables', 'Duration' => '0.000559' 
    - 'Status' => 'System lock', 'Duration' => '0.000002' 
    - 'Status' => 'Table lock', 'Duration' => '0.000006' 
    - 'Status' => 'init', 'Duration' => '0.000019' 
    - 'Status' => 'checking permissions', 'Duration' => '0.000001' 
    - 'Status' => 'checking permissions', 'Duration' => '0.000030' 
    - 'Status' => 'optimizing', 'Duration' => '0.000018' 
    - 'Status' => 'statistics', 'Duration' => '0.000025' 
    - 'Status' => 'preparing', 'Duration' => '0.000015' 
    - 'Status' => 'Creating tmp table', 'Duration' => '0.001828' 
    - 'Status' => 'executing', 'Duration' => '0.000001' 
    - 'Status' => 'Copying to tmp table', 'Duration' => '0.958071' 
    - 'Status' => 'Sorting result', 'Duration' => '0.013502' 
    - 'Status' => 'Sending data', 'Duration' => '0.088148' 
    - 'Status' => 'end', 'Duration' => '0.000003' 
    - 'Status' => 'removing tmp table', 'Duration' => '0.002037' 
    - 'Status' => 'end', 'Duration' => '0.000003' 
    - 'Status' => 'query end', 'Duration' => '0.000001' 
    - 'Status' => 'freeing items', 'Duration' => '0.000112' 
    - 'Status' => 'logging slow query', 'Duration' => '0.000001' 
    - 'Status' => 'cleaning up', 'Duration' => '0.000004' 

解釋說:

在訂購

|-id-|-select_type-|-table----|-type---|-possible_keys--------|-key-----------------|-key_len-|-ref-------------------------------------|-rows--|-Extra 
|-1--|-SIMPLE------|-s--------|-ALL----|-PRIMARY,search_index-|-NULL----------------|-NULL----|-NULL------------------------------------|-92166-|-Using temporary; Using filesort 
|-1--|-SIMPLE------|-tags-----|-eq_ref-|-PRIMARY--------------|-PRIMARY-------------|-426-----|-apiv2.s.item_id,apiv2.s.item_type,const-|-1-----|-Using where; Using index 
|-1--|-SIMPLE------|-featured-|-ref----|-type_position_index--|-type_position_index-|-62------|-const-----------------------------------|-3-----|-Using index 

不需預定

|-id-|-select_type-|-table----|-type---|-possible_keys--------|-key-----------------|-key_len-|-ref-------------------------------------|-rows--|-Extra 
|-1--|-SIMPLE------|-s--------|-ALL----|-PRIMARY,search_index-|-NULL----------------|-NULL----|-NULL------------------------------------|-88346-|- 
|-1--|-SIMPLE------|-tags-----|-eq_ref-|-PRIMARY--------------|-PRIMARY-------------|-426-----|-apiv2.s.item_id,apiv2.s.item_type,const-|-1-----|-Using where; Using index 
|-1--|-SIMPLE------|-featured-|-ref----|-type_position_index--|-type_position_index-|-62------|-const-----------------------------------|-3-----|-Using index 

表:search_all

CREATE TABLE `search_all` ( 
    `item_id` varchar(20) NOT NULL DEFAULT '', 
    `item_type` varchar(20) NOT NULL DEFAULT '', 
    `title` varchar(255) DEFAULT NULL, 
    `caption` text, 
    `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 
    PRIMARY KEY (`item_id`,`item_type`), 
    UNIQUE KEY `search_index` (`item_id`,`item_type`,`date`), 
    KEY `date_index` (`date`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 


|-id-|-select_type-|-table------|-type-|-possible_keys-|-key--|-key_len-|-ref--|-rows--|-Extra 
|-1--|-SIMPLE------|-search_all-|-ALL--|-NULL----------|-NULL-|-NULL----|-NULL-|-74785-|- 

表:標籤

CREATE TABLE `tags` ( 
    `tag` varchar(100) NOT NULL DEFAULT '', 
    `updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 
    `item_id` varchar(20) NOT NULL DEFAULT '', 
    `item_type` varchar(20) NOT NULL DEFAULT '', 
    PRIMARY KEY (`item_id`,`item_type`,`tag`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 


|-id-|-select_type-|-table-|-type--|-possible_keys-|-key-----|-key_len-|-ref--|-rows---|-Extra 
|-1--|-SIMPLE------|-tags--|-index-|-NULL----------|-PRIMARY-|-426-----|-NULL-|-197400-|-Using index 

表:功能

CREATE TABLE `featured` ( 
    `position` int(10) NOT NULL DEFAULT '0', 
    `item_type` varchar(20) NOT NULL DEFAULT '', 
    `item_id` varchar(20) NOT NULL DEFAULT '', 
    `feature_type` varchar(20) NOT NULL DEFAULT '', 
    PRIMARY KEY (`position`,`item_type`,`item_id`,`feature_type`), 
    KEY `type_position_index` (`feature_type`,`position`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 


|-id-|-select_type-|-table----|-type--|-possible_keys-|-key-----------------|-key_len-|-ref--|-rows-|-Extra 
|-1--|-SIMPLE------|-featured-|-index-|-NULL----------|-type_position_index-|-66------|-NULL-|-13---|-Using index 

爲什麼PDO中的無序或PHP中的MSQL沒有區別?有什麼辦法可以讓它變得更快嗎?

+3

發佈查詢的表定義(包括索引)和(EXPLAIN)執行計劃。 –

+0

你真的能重現嗎? 「發送數據」似乎在最後一個示例中消耗了太多時間。也許它只是一個「滯後」或緩存問題。 – KingCrunch

+1

我相信時間是在配置文件中的每一步的開始時檢查的,這意味着長時間的時間實際上是對前一步驟的錯誤評論,這會將所有手指指向「正在執行」的步驟 – Ripptor

回答

5

除非您的訂單是針對索引列的,並且優化器認爲使用索引是一個好主意,則「ORDER BY」將導致需要大量時間和資源的任何大小的結果集。

PDO版本耗時較長的原因是您的腳本消耗的行數比SQLServer可以提供的速度慢,因此數據庫正在等待您的程序。由於您使用的是一種解釋型語言和一種對行結果進行大量操作的API,因此這只是預料之中。這種「發送數據」的延遲要比排序的開銷大得多(0.75秒和1.04秒)。

請注意,緩慢的檢索是由順序複合。在無序SQL的情況下,行將在選擇後立即發送。在有序選擇的情況下,所有行都將被選中,然後在發送第一個結果行之前進行排序。

+1

我有一個位置的索引,但由於大多數行沒有加入精選,大多數不會有位置。我已經實現了PHP排序來跳過MYSQL端的排序,但是由於刪除排序並沒有加快速度,我沒有任何改進。如果我可以加快無序的PDO,那麼我認爲它可以工作。你有沒有建議呢? – Ripptor

0

你可以請張貼表定義(字段,字段的類型等)?

我先上datesearch_alltagtags添加一個簡單的索引和

一個簡單的索引。

+0

已添加表格定義。在search_all中有一個日期索引,而tags表是一個三鍵(item_id,item_type,tag) – Ripptor

+0

@Ripptor:索引'(tag)'與索引'(item_id,item_type,tag) –