2011-11-07 53 views
1

我們的數據庫已設置好,因此我們有一個包含多種不同類型憑證(登錄等)的credentials表。還有一個將某些類型關聯在一起的credential_pairs表(例如,用戶可能有密碼和安全令牌)。在MySQL慢查詢日誌中優化查詢

在嘗試,看是否有對比賽,有以下查詢:

SELECT DISTINCT cp.credential_id FROM credential_pairs AS cp 
INNER JOIN credentials AS c1 ON (cp.primary_credential_id = c1.credential_id) 
INNER JOIN credentials AS c2 ON (cp.secondary_credential_id = c2.credential_id) 
WHERE c1.data = AES_ENCRYPT('Some Value 1', 'encryption key') 
AND c2.data = AES_ENCRYPT('Some Value 2', 'encryption key'); 

此查詢工作正常,給我們正是我們需要的。但是,它一直在緩慢的查詢日誌中顯示(可能是由於缺乏索引?)。當我問MySQL來「解釋」查詢它給了我:

+----+-------------+-------+------+--------------------------------------------------------+---------------------+---------+-------+-------+--------------------------------+ 
| id | select_type | table | type | possible_keys           | key     | key_len | ref | rows | Extra       | 
+----+-------------+-------+------+--------------------------------------------------------+---------------------+---------+-------+-------+--------------------------------+ 
| 1 | SIMPLE  | c1 | ref | credential_id_UNIQUE,credential_id,ix_credentials_data | ix_credentials_data | 22  | const |  1 | Using where; Using temporary | 
| 1 | SIMPLE  | c2 | ref | credential_id_UNIQUE,credential_id,ix_credentials_data | ix_credentials_data | 22  | const |  1 | Using where     | 
| 1 | SIMPLE  | cp | ALL | NULL             | NULL    | NULL | NULL | 69197 | Using where; Using join buffer | 
+----+-------------+-------+------+--------------------------------------------------------+---------------------+---------+-------+-------+--------------------------------+ 

我有一種感覺,最後一個條目(如果它顯示69197行)可能是問題,但我從一個DBA很遠......幫幫我?


憑證表:

CREATE TABLE `credentials` (
    `hidden_id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `credential_id` varchar(255) NOT NULL, 
    `data` blob NOT NULL, 
    `credential_status` varchar(100) NOT NULL, 
    `insert_date` datetime NOT NULL, 
    `insert_user` int(10) unsigned NOT NULL, 
    `update_date` datetime DEFAULT NULL, 
    `update_user` int(10) unsigned DEFAULT NULL, 
    `delete_date` datetime DEFAULT NULL, 
    `delete_user` int(10) unsigned DEFAULT NULL, 
    `is_deleted` tinyint(1) NOT NULL DEFAULT '0', 
    PRIMARY KEY (`hidden_id`,`credential_id`), 
    UNIQUE KEY `credential_id_UNIQUE` (`credential_id`), 
    KEY `credential_id` (`credential_id`), 
    KEY `data` (`data`(10)), 
    KEY `credential_status` (`credential_status`(10)) 
) ENGINE=InnoDB AUTO_INCREMENT=1572 DEFAULT CHARSET=utf8; 

credential_pairs表:

CREATE TABLE `credential_pairs` (
    `hidden_id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `credential_id` varchar(255) NOT NULL, 
    `primary_credential_id` varchar(255) NOT NULL, 
    `secondary_credential_id` varchar(255) NOT NULL, 
    `is_deleted` tinyint(1) DEFAULT NULL, 
    PRIMARY KEY (`hidden_id`,`credential_id`), 
    KEY `primary_credential_id` (`primary_credential_id`(10)), 
    KEY `secondary_credential_id` (`secondary_credential_id`(10)) 
) ENGINE=InnoDB AUTO_INCREMENT=500 DEFAULT CHARSET=latin1; 

憑證索引:

+-------------+------------+----------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+ 
| Table  | Non_unique | Key_name    | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type  | Comment | 
+-------------+------------+----------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+ 
| credentials |   0 | PRIMARY    |   1 | hidden_id  | A   |  186235 |  NULL | NULL |  | BTREE  |   | 
| credentials |   0 | PRIMARY    |   2 | credential_id | A   |  186235 |  NULL | NULL |  | BTREE  |   | 
| credentials |   0 | credential_id_UNIQUE |   1 | credential_id | A   |  186235 |  NULL | NULL |  | BTREE  |   | 
| credentials |   1 | credential_id  |   1 | credential_id | A   |  186235 |  NULL | NULL |  | BTREE  |   | 
| credentials |   1 | ix_credentials_data |   1 | data   | A   |  186235 |  20 | NULL |  | BTREE  |   | 
+-------------+------------+----------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+ 

credential_pair指標:

+------------------+------------+---------------------------------------------+--------------+-------------------------+-----------+-------------+----------+--------+------+------------+---------+ 
| Table   | Non_unique | Key_name         | Seq_in_index | Column_name    | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | 
+------------------+------------+---------------------------------------------+--------------+-------------------------+-----------+-------------+----------+--------+------+------------+---------+ 
| credential_pairs |   0 | PRIMARY          |   1 | hidden_id    | A   |  69224 |  NULL | NULL |  | BTREE  |   | 
| credential_pairs |   0 | PRIMARY          |   2 | credential_id   | A   |  69224 |  NULL | NULL |  | BTREE  |   | 
| credential_pairs |   1 | ix_credential_pairs_credential_id   |   1 | credential_id   | A   |  69224 |  36 | NULL |  | BTREE  |   | 
| credential_pairs |   1 | ix_credential_pairs_primary_credential_id |   1 | primary_credential_id | A   |  69224 |  36 | NULL |  | BTREE  |   | 
| credential_pairs |   1 | ix_credential_pairs_secondary_credential_id |   1 | secondary_credential_id | A   |  69224 |  36 | NULL |  | BTREE  |   | 
+------------------+------------+---------------------------------------------+--------------+-------------------------+-----------+-------------+----------+--------+------+------------+---------+ 

更新備註:

AFAICT:本DISTINCT是多餘的......真的沒什麼需要它,所以我放棄了它。在試圖遵循法布里奇奧的建議得到對credential_pairs查找一個,我則改變了語句來爲已讀:

SELECT credential_id 
FROM credential_pairs cp 
WHERE cp.primary_credential_id = (SELECT credential_id FROM credentials WHERE data = AES_ENCRYPT('value 1','enc_key')) AND 
    cp.secondary_credential_id = (SELECT credential_id FROM credentials WHERE data = AES_ENCRYPT('value 2','enc_key')) 

與....無關。該聲明只需要很長時間,解釋看起來幾乎相同。所以,我給主要和次要列添加了一個索引:

ALTER TABLE credential_pairs ADD INDEX `idx_credential_pairs__primary_and_secondary`(`primary_credential_id`, `secondary_credential_id`); 

而且......沒什麼。

+----+-------------+-------------+-------+---------------------+---------------------------------------------+---------+------+-------+--------------------------+ 
| id | select_type | table  | type | possible_keys  | key           | key_len | ref | rows | Extra     | 
+----+-------------+-------------+-------+---------------------+---------------------------------------------+---------+------+-------+--------------------------+ 
| 1 | PRIMARY  | cp   | index | NULL    | idx_credential_pairs__primary_and_secondary | 514  | NULL | 69217 | Using where; Using index | 
| 3 | SUBQUERY | credentials | ref | ix_credentials_data | ix_credentials_data       | 22  |  |  1 | Using where    | 
| 2 | SUBQUERY | credentials | ref | ix_credentials_data | ix_credentials_data       | 22  |  |  1 | Using where    | 
+----+-------------+-------------+-------+---------------------+---------------------------------------------+---------+------+-------+--------------------------+ 

它說它使用索引,但它仍然看起來像它的表掃描。所以,我添加了一個聯合鍵(按下面a'r的評論)有:

ALTER TABLE credential_pairs ADD KEY (primary_credential_id, secondary_credential_id); 

而且......相同的結果與指數(是這些功能一樣嗎?)。

+0

嘗試選擇表上credential_pairs添加組合鍵,例如,在過去的運氣。 'ALTER TABLE credential_pairs ADD KEY(primary_credential_id,secondary_credential_id);' –

+0

你最初是否試圖找到與給定的一組值相匹配的所有對(「某個值1」和「某個值2」)?因爲這是查詢所做的事情。無法使此查詢更快,因爲它始終必須進行全表掃描。它在設計中看起來是一個錯誤,因爲通常你應該有一個用戶並且知道他的credential_id。一旦他提供了令牌值,就可以使用此憑證ID查找屬於他的對(僅掃描一對和一行),然後根據輸入的令牌值驗證該對中的主憑證和輔助憑證。 –

回答

0

的DISTINCT是什麼產生了「使用臨時」,你平時要避免那些可能時

另外,你要掃描整個credential_pair表作爲你沒有反對任何條件,使不使用索引和WHERE

希望這是有道理的

編輯整個表應用之前返回/由加載

嘗試從不同的表開始,如果我理解正確的話,你有表A,表B和表AB,並且你從AB開始選擇,嘗試從A開始它A

我還沒有測試過這個,但是你可以嘗試:

SELECT cp.credential_id 
FROM credentials AS c1 
    LEFT JOIN credential_pairs AS cp ON (c1.credential_id = cp.primary_credential_id) 
    LEFT JOIN credentials AS c2 ON (cp.secondary_credential_id = c2.credential_id) 
WHERE 
    c1.data = AES_ENCRYPT('Some Value 1', 'encryption key') 
    AND c2.data = AES_ENCRYPT('Some Value 2', 'encryption key'); 

我已經走動

+0

試過幾件事(包括,我希望你的建議)....更新了問題。 –

+0

實際添加的內容可能會減慢查詢速度。我相信在WHERE中添加一個(SELECT)只會導致爲每個值執行子查詢 – Fabrizio

+0

仍然需要大約相同的時間才能通過它們來攪動.... :( –