2009-09-19 7 views
0

(MySQLの4.1.22を使用して)ヘルプは、私は私のこのクエリは大きなテーブルの上に(20万+行)インデックスを使用して取得することはできません、それはそれでフルテーブルスキャンを行っているMySQLのクエリ

を最適化します。クエリは現在約1.2秒かかります。可能であれば、2秒未満にしたいと思っています。それは、インデックスを使用していないので、明らかに問題は「by_user」に参加している

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, '' 

:説明の

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 

結果:

は、ここに私のクエリです。

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にはどのようなインデックスがありますか? –

+0

あなたはどのインデックスを定義しましたか? –

+0

私はちょうどst_issuesの定義を追加しました – Echo

答えて

3

は、全体のことですユーザーテーブルの定義?

それが言うので:

を)ENGINE = InnoDBは

st_issuesに対し、こう述べています。

= UTF8)ENGINE = InnoDBのデフォルトの文字セット。

あなたの二つのテーブルが異なる照合順序を使用している場合は、uidとcreated_by_uidのための2つの文字列のデータ型が異なり、MySQLは、それはこのようにあなたのインデックスを破って、それらを比較することができます前に、文字は強制を設定しなければなりません。

データベース内のすべてのテキストに同じ文字セットまたは照合順序を使用することを常にお勧めします。

+0

ああ、それは問題が何であるか、おかげです。 – Echo

0

私はいくつかのテストを行なったし、助けた次の変更が見つかりました:

  • st_issues.assigned_cidにインデックスを追加します。

  • uidの代わりにusersテーブルの主キーをcidに変更します。by_usercid代わりのuidを使用するため

  • 変更条件に参加:

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

Iまし以下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、カテゴリまたはステータスの名前を定義することです。その後、tinyint仮名を使用する代わりに、st_issuesテーブルからその自然キーを参照してください。利点は、カテゴリまたはステータスの名前を取得するためにこれらの結合を実行する必要がないことです。すでにst_issuesテーブルにあります。

関連する問題