2009-09-19 115 views
0

(使用MySQL 4.1.22)幫助優化MySQL查詢

我不能讓我的這個查詢在大表上使用索引(200K +行),它做就可以了全表掃描。查詢現在需要大約1.2秒。如果可能,我想把它縮短到不到0.2秒。

這裏是我的查詢:

SELECT st_issues.issue_id, st_issues.cat_id,st_categories.name AS cat_name, st_issues.status_id,st_statuses.name AS status_name, st_issues.priority_id,st_priorities.name AS priority_name,st_priorities.color AS color, st_issues.assigned_cid,assigned_u.firstname,assigned_u.lastname,assigned_u.screenname, message, rating, created_by_email,created_by_cid,created_by_uid,by_user.firstname AS by_firstname,by_user.lastname AS by_lastname,by_user.screenname AS by_screenname, st_issues.browser,from_url,created_by_store,created,st_issues.stamp 
FROM st_issues 
JOIN st_categories ON (st_issues.cat_id=st_categories.cat_id) 
JOIN st_statuses ON (st_issues.status_id=st_statuses.status_id) 
JOIN st_priorities ON (st_issues.priority_id=st_priorities.priority_id) 
LEFT JOIN users AS assigned_u ON (assigned_u.cid=st_issues.assigned_cid) 
LEFT JOIN users AS by_user ON (by_user.uid=st_issues.created_by_uid) 
LEFT JOIN st_issue_changes ON (st_issues.issue_id=st_issue_changes.issue_id AND change_id=0) 
WHERE st_issues.assigned_cid=0 

解釋的結果:

1, 'SIMPLE', 'st_issues', 'ALL', '', '', , '', 4, 'Using where' 
1, 'SIMPLE', 'st_categories', 'eq_ref', 'PRIMARY', 'PRIMARY', 1, 'sg.st_issues.cat_id', 1, '' 
1, 'SIMPLE', 'st_priorities', 'eq_ref', 'PRIMARY', 'PRIMARY', 1, 'sg.st_issues.priority_id', 1, '' 
1, 'SIMPLE', 'assigned_u', 'ref', 'cid', 'cid', 8, 'sg.st_issues.assigned_cid', 1, '' 
1, 'SIMPLE', 'st_statuses', 'ALL', 'PRIMARY', '', , '', 4, 'Using where' 
1, 'SIMPLE', 'by_user', 'ALL', '', '', , '', 221623, '' 
1, 'SIMPLE', 'st_issue_changes', 'eq_ref', 'PRIMARY', 'PRIMARY', 6, 'sg.st_issues.issue_id,const', 1, '' 

顯然問題出在加入上「by_user」,因爲它不使用索引。

下面是一些「用戶」表的定義:

CREATE TABLE `users` (
    `cid` double unsigned NOT NULL auto_increment, 
    `uid` varchar(20) NOT NULL default '', 
... 
    `firstname` varchar(20) default NULL, 
    `lastname` varchar(20) default NULL, 
... 
    PRIMARY KEY (`uid`), 
... 
) ENGINE=InnoDB 

任何人有爲什麼它不使用連接中的主鍵的任何想法?
任何人有任何想法或提示如何加快此查詢更多?

(我可以添加其他表的表定義,如果需要/想)

編輯:

這裏是st_issues表定義:

CREATE TABLE `st_issues` (
    `issue_id` int(10) unsigned NOT NULL auto_increment, 
    `cat_id` tinyint(3) unsigned NOT NULL default '0', 
    `status_id` tinyint(3) unsigned NOT NULL default '0', 
    `priority_id` tinyint(3) unsigned NOT NULL default '0', 
    `assigned_cid` int(10) unsigned NOT NULL default '0', 
    `rating` tinyint(4) default NULL, 
    `created_by_email` varchar(255) NOT NULL default '', 
    `created_by_cid` int(10) unsigned NOT NULL default '0', 
    `created_by_uid` varchar(20) NOT NULL default '', 
    `created_by_store` tinyint(3) unsigned NOT NULL default '0', 
    `browser` varchar(255) NOT NULL default '', 
    `from_url` varchar(255) NOT NULL default '', 
    `created` datetime NOT NULL default '0000-00-00 00:00:00', 
    `stamp` datetime NOT NULL default '0000-00-00 00:00:00', 
    PRIMARY KEY (`issue_id`), 
    KEY `idx_create_by_cid` (`created_by_cid`), 
    KEY `idx_create_by_uid` (`created_by_uid`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 
+0

你對st_issues有什麼索引? – 2009-09-19 15:40:11

+0

您定義了哪些索引? – 2009-09-19 15:40:13

+0

我剛剛添加了st_issues的定義 – Echo 2009-09-19 15:44:40

回答

3

是整個的用戶表的定義?

因爲它說:

)ENGINE = InnoDB的

而st_issues說:

)ENGINE = InnoDB的默認字符集= UTF8;

如果你的兩個表可以使用不同的排序規則,對uid和created_by_uid兩個字符串數據類型是不同的,和MySQL必須做一個字符集的強制,纔可以對它們進行比較,從而擊敗你的索引。

確保您對數據庫中的所有文本使用相同的字符集/排序規則總是最好的。

+0

啊,我敢打賭這就是問題所在,謝謝。 – Echo 2009-09-19 16:33:32

0

我做了一些測試,發現了以下更改幫助:

  • st_issues.assigned_cid添加索引。

  • users表的主鍵改爲cid而不是uid

  • 變化的連接條件by_user使用cid而不是uid

    LEFT JOIN users AS by_user ON (by_user.cid=st_issues.created_by_cid) 
    

然後我得到了以下EXPLAIN報告(雖然零行數據):

+----+-------------+------------------+--------+---------------+--------------+---------+-------------------------------+------+-------------+ 
| id | select_type | table   | type | possible_keys | key   | key_len | ref       | rows | Extra  | 
+----+-------------+------------------+--------+---------------+--------------+---------+-------------------------------+------+-------------+ 
| 1 | SIMPLE  | st_issues  | ref | assigned_cid | assigned_cid | 4  | const       | 1 |    | 
| 1 | SIMPLE  | st_categories | eq_ref | PRIMARY  | PRIMARY  | 1  | test.st_issues.cat_id   | 1 |    | 
| 1 | SIMPLE  | st_statuses  | eq_ref | PRIMARY  | PRIMARY  | 1  | test.st_issues.status_id  | 1 |    | 
| 1 | SIMPLE  | st_priorities | eq_ref | PRIMARY  | PRIMARY  | 1  | test.st_issues.priority_id | 1 |    | 
| 1 | SIMPLE  | assigned_u  | eq_ref | PRIMARY  | PRIMARY  | 8  | test.st_issues.assigned_cid | 1 |    | 
| 1 | SIMPLE  | by_user   | eq_ref | PRIMARY  | PRIMARY  | 8  | test.st_issues.created_by_cid | 1 |    | 
| 1 | SIMPLE  | st_issue_changes | eq_ref | PRIMARY  | PRIMARY  | 8  | test.st_issues.issue_id,const | 1 | Using index | 
+----+-------------+------------------+--------+---------------+--------------+---------+-------------------------------+------+-------------+ 

這表明優化器爲每個表選擇了一個索引,而不是在您的查詢版本中。我不得不猜測你的查找表的定義。

另一件事,我建議是定義查找表st_categoriesst_statuses自然鍵,類別或狀態的名稱。然後從st_issues表中引用該自然鍵,而不是使用tinyint僞碼。好處是您不必執行這些連接來獲取類別或狀態的名稱;它已經在st_issues表中。