我有一個非常簡單的模式的MySQL數據庫。有parent
,child
和access
表。MySQL數據庫性能調優,模式優化
parent
存儲51個字段都是varchar
(其長度從16到512)除了用於4個longtext
字段和主鍵這是一個bigint
。除主鍵外,還有其他3個字段的索引。一個以便child
表可以將它作爲外鍵引用。
child
存儲23個字段,大多數爲varchar
,其中有一些text
字段。 A varchar(256)
字段用作將其鏈接到父項的外鍵。不過,外鍵字段的實際內容預計都會少於60個字符。
accesss
有bigint
場和varchar
場一起構成主鍵和bigint
領域是它鏈接到parent
外鍵。
access
表用於指定哪些用戶有權訪問parent
中的哪些記錄。可能有多個用戶應該有權訪問任何記錄。
有大約在parent
(因此
和周圍2E7行。編輯:對不起,access
)2E6行中
child
access
有5329840行。即對於parent
中的每一行,在access
中有一行或多行。
上述架構基於我們希望遷移到MySQL的舊版FileMaker數據庫。我相信這不是理想的,但我不知道爲什麼。
根據參數,查詢很快或很慢。所以,例如如果存在bob
有權訪問的多條記錄,以下查詢將需要一兩秒鐘的時間。查詢需要幾分鐘的時間(如12分鐘),不過,如果沒有記錄該用戶bob
訪問(例如,如果沒有用戶名爲bob
):
SELECT
p."RecordID", p."SerialNumber", p."Folder", p."NoteType",
p."FirstName", p."LastName", p."DOB", p."Body", p."From",
p."DateTxt", a."UserName" AS Access
FROM parent AS p
INNER JOIN access AS a ON a."RecordID" = p."RecordID"
WHERE p."RecordID" > 123
AND a."UserName" = 'bob'
ORDER BY p."RecordID"
LIMIT 500;
這裏是EXPLAIN
說,有關查詢:
+----+-------------+-------+--------+---------------+---------+---------+---------------------+--------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+---------------------+--------+--------------------------+
| 1 | SIMPLE | p | range | PRIMARY | PRIMARY | 8 | NULL | 731752 | Using where |
| 1 | SIMPLE | a | eq_ref | PRIMARY | PRIMARY | 74 | db.p.RecordID,const | 1 | Using where; Using index |
+----+-------------+-------+--------+---------------+---------+---------+---------------------+--------+--------------------------+
2 rows in set (0.01 sec)
那麼,有沒有辦法加快不匹配的查詢?這可能是由於使用varchar /文本字段的一切?將一個varchar(256)字段用作外鍵會導致問題(儘管它不在上面的查詢中使用)?或者是查詢責備?
編輯:我剛剛意識到PRIMARY KEY ("RecordID", "UserName")
的access
表不被用於SELECT ... FROM access WHERE UserName = 'blah'
。我在UserName列創建了一個索引,並且似乎解決了這個問題。如果有人有任何建議,我仍然會很感激。
當前的EXPLAIN
輸出:
+----+-------------+-------+--------+---------------+---------+---------+---------------------+--------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+---------------------+--------+--------------------------+
| 1 | SIMPLE | p | range | PRIMARY | PRIMARY | 8 | NULL | 605020 | Using where |
| 1 | SIMPLE | a | eq_ref | PRIMARY,UNidx | PRIMARY | 74 | db.p.RecordID,const | 1 | Using where; Using index |
+----+-------------+-------+--------+---------------+---------+---------+---------------------+--------+--------------------------+
2 rows in set (0.00 sec)
編輯:@ DRapp的建議確實產生巨大的變化。 access.UserName上的查詢很快,有或沒有索引。如果我放棄索引並嘗試不使用STRAIGHT_JOIN
的DRapp查詢,那麼它又很慢。
DRapp的查詢,而指數access.UserName:
mysql> explain SELECT STRAIGHT_JOIN p."RecordID", p."SerialNumber", p."Folder", p."NoteType", p."FirstName", p."LastName", p."DOB", p."Body", p."From", p."DateTxt", a."UserName" AS Access FROM access as a, parent AS p where a."UserName" = 'bob' and a."RecordID" > 123 and a."RecordID" = p."RecordID" order by a."RecordID" limit 500;
+----+-------------+-------+--------+---------------+---------+---------+---------------+---------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+---------------+---------+--------------------------+
| 1 | SIMPLE | a | range | PRIMARY | PRIMARY | 8 | NULL | 2382668 | Using where; Using index |
| 1 | SIMPLE | p | eq_ref | PRIMARY | PRIMARY | 8 | bb.a.RecordID | 1 | |
+----+-------------+-------+--------+---------------+---------+---------+---------------+---------+--------------------------+
2 rows in set (0.00 sec)
與指數access.UserName
相同的查詢:
mysql> explain SELECT STRAIGHT_JOIN ...;
+----+-------------+-------+--------+---------------+---------+---------+---------------+---------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+---------------+---------+--------------------------+
| 1 | SIMPLE | a | ref | PRIMARY,UNidx | UNidx | 66 | const | 1209780 | Using where; Using index |
| 1 | SIMPLE | p | eq_ref | PRIMARY | PRIMARY | 8 | db.a.RecordID | 1 | |
+----+-------------+-------+--------+---------------+---------+---------+---------------+---------+--------------------------+
2 rows in set (0.00 sec)
而不指數access.UserName
和不相同的查詢的STRAIGHT_JOIN
:
mysql> explain SELECT p."RecordID", p."SerialNumber", p."Folder", p."NoteType", p."FirstName", p."LastName", p."DOB", p."Body", p."From", p."DateTxt", a."UserName" AS Access FROM access as a, parent AS p where a."UserName" = 'zzz' and a."RecordID" > 123 and a."RecordID" = p."RecordID" order by a."RecordID" limit 500;
+----+-------------+-------+--------+---------------+---------+---------+---------------------+--------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+---------------------+--------+----------------------------------------------+
| 1 | SIMPLE | p | range | PRIMARY | PRIMARY | 8 | NULL | 484016 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | a | eq_ref | PRIMARY | PRIMARY | 74 | db.p.RecordID,const | 1 | Using where; Using index |
+----+-------------+-------+--------+---------------+---------+---------+---------------------+--------+----------------------------------------------+
2 rows in set (0.00 sec)
謝謝。之前從未聽說過STRAIGHT_JOIN。查找它。 – Wodin 2011-01-24 12:16:21