2011-01-24 54 views
1

我有一個非常簡單的模式的MySQL數據庫。有parentchildaccess表。MySQL數據庫性能調優,模式優化

parent存儲51個字段都是varchar(其長度從16到512)除了用於4個longtext字段和主鍵這是一個bigint。除主鍵外,還有其他3個字段的索引。一個以便child表可以將它作爲外鍵引用。

child存儲23個字段,大多數爲varchar,其中有一些text字段。 A varchar(256)字段用作將其鏈接到父項的外鍵。不過,外鍵字段的實際內容預計都會少於60個字符。

accesssbigint場和varchar場一起構成主鍵和bigint領域是它鏈接到parent外鍵。

access表用於指定哪些用戶有權訪問parent中的哪些記錄。可能有多個用戶應該有權訪問任何記錄。

有大約在parent (因此 access)2E6行中 child 和周圍2E7行。編輯:對不起,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) 

回答

1

我一直都很好l在MySQL中使用「STRAIGHT_JOIN」子句,並將主表基礎作爲第一個排在修飾符列表中。在這種情況下,您的「Access」表尋找Bob,然後查看Bob有權查看的記錄。如果它在ACCESS查詢中失敗,則不需要更深入。此外,由於連接基於相同的「RecordID」,因此我已更改對「a」的引用。表。由於此查詢首先基於用戶名,因此我也有一個關鍵字。我會對它的解釋和性能感興趣。

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 
+0

謝謝。之前從未聽說過STRAIGHT_JOIN。查找它。 – Wodin 2011-01-24 12:16:21