2011-10-17 26 views
0

我一直在運行在MySQL慢日誌由於生產問題和頭號查詢:我能做些什麼來使這個SQL更有效? (表有850K行)

select * from feeditem feeditem0_ where feeditem0_.importance=0 and feeditem0_.company_id=N limit 21; 

我已經縮寫選擇(N是一個id爲FK )作爲它從休眠生成的,它只是選擇該表中的所有字段。當我做一個mysql解釋我得到:

explain select * from feeditem feeditem0_ where feeditem0_.importance=0 and feeditem0_.company_id=5045 limit 21 \G;; 
*************************** 1. row *************************** 
     id: 1 
select_type: SIMPLE 
    table: feeditem0_ 
    type: index_merge 
possible_keys: FKF49961B13D5FD8EF,importance 
     key: FKF49961B13D5FD8EF,importance 
    key_len: 9,5 
     ref: NULL 
    rows: 2422 
    Extra: Using intersect(FKF49961B13D5FD8EF,importance); Using where 

該表中約有850K行。

的模式是:

CREATE TABLE `feeditem` (
`DTYPE` varchar(31) NOT NULL, 
`id` bigint(20) NOT NULL AUTO_INCREMENT, 
`dateCreated` datetime DEFAULT NULL, 
`endSentance` varchar(255) DEFAULT NULL, 
`importance` int(11) DEFAULT NULL, 
`startSentance` varchar(255) DEFAULT NULL, 
`summary` varchar(255) DEFAULT NULL, 
`summaryComplete` bit(1) NOT NULL, 
`targetId` bigint(20) DEFAULT NULL, 
`targetSentance` text, 
`type` varchar(255) NOT NULL, 
`hasRead` bit(1) DEFAULT NULL, 
`teamProject_id` bigint(20) DEFAULT NULL, 
`user_id` bigint(20) DEFAULT NULL, 
`usertoread_id` bigint(20) DEFAULT NULL, 
`contentType` varchar(255) DEFAULT NULL, 
`company_id` bigint(20) DEFAULT NULL, 
`updated` int(1) unsigned DEFAULT NULL, 
`feedType` varchar(255) DEFAULT NULL, 
`extraInfo` varchar(255) DEFAULT NULL, 
`extraTargetId` bigint(20) DEFAULT NULL, 
PRIMARY KEY (`id`), 
KEY `FKF49961B1B74A2DA5` (`user_id`), 
KEY `FKF49961B17CE9E5EF` (`teamProject_id`), 
KEY `FKF49961B137B7D1B4` (`usertoread_id`), 
KEY `FKF49961B13D5FD8EF` (`company_id`), 
KEY `importance` (`importance`), 
KEY `dateCreated` (`dateCreated`) 
) ENGINE=InnoDB AUTO_INCREMENT=956498 DEFAULT CHARSET=utf8 

有什麼辦法,我得到制止被掃描的2400個奇數行?這是從慢日誌(使用mysqlsla)摘要:

Count   : 61 (53.98%) 
Time   : 523 s total, 8.57377 s avg, 6 s to 19 s max (54.03%) 
95% of Time : 456 s total, 8 s avg, 6 s to 14 s max 
Lock Time (s) : 0 total, 0 avg, 0 to 0 max (0.00%) 
95% of Lock : 0 total, 0 avg, 0 to 0 max 
Rows sent  : 34 avg, 21 to 51 max (38.69%) 
Rows examined : 3.49k avg, 40 to 8.89k max (0.00%) 
Users   :100.00% (61) of query, 100.00% (113) of all users 

感謝

更新1:我加2山坳指數(稱爲feedquery),但它似乎對優化器選擇不使用指數:

mysql> explain select id from feeditem feeditem0_ where feeditem0_.importance=0 and feeditem0_.company_id=5045 \G; 
*************************** 1. row *************************** 
     id: 1 
    select_type: SIMPLE 
    table: feeditem0_ 
    type: index_merge 
possible_keys: FKF49961B13D5FD8EF,importance,feedquery 
     key: FKF49961B13D5FD8EF,feedquery 
    key_len: 9,14 
     ref: NULL 
    rows: 2753 
    Extra: Using intersect(FKF49961B13D5FD8EF,feedquery); Using where; Using index 

如果我忽略指數:

explain select id from feeditem feeditem0_ ignore index (FKF49961B13D5FD8EF) where feeditem0_.importance=0 and feeditem0_.company_id=5045 \G; 
*************************** 1. row *************************** 
     id: 1 
select_type: SIMPLE 
    table: feeditem0_ 
    type: ref 
possible_keys: importance,feedquery 
     key: feedquery 
    key_len: 14 
     ref: const,const 
    rows: 8496 
    Extra: Using where; Using index 

表:

CREATE TABLE `feeditem` (
..... 
PRIMARY KEY (`id`), 
KEY `FKF49961B1B74A2DA5` (`user_id`), 
KEY `FKF49961B17CE9E5EF` (`teamProject_id`), 
KEY `FKF49961B137B7D1B4` (`usertoread_id`), 
KEY `FKF49961B13D5FD8EF` (`company_id`), 
KEY `importance` (`importance`), 
KEY `dateCreated` (`dateCreated`), 
KEY `feedquery` (`importance`,`company_id`) 
) ENGINE=InnoDB AUTO_INCREMENT=999359 DEFAULT CHARSET=utf8 

更新2: @Salman一個

SHOW profile; 
+----------------------+----------+ 
| Status    | Duration | 
+----------------------+----------+ 
| starting    | 0.000342 | 
| checking permissions | 0.000024 | 
| Opening tables  | 0.000053 | 
| System lock   | 0.000027 | 
| init     | 0.000166 | 
| optimizing   | 0.000068 | 
| statistics   | 0.012869 | 
| preparing   | 0.000202 | 
| executing   | 0.000008 | 
| Sending data   | 0.332767 | 
| end     | 0.000022 | 
| query end   | 0.000009 | 
| closing tables  | 0.000016 | 
| freeing items  | 0.000040 | 
| logging slow query | 0.000005 | 
| cleaning up   | 0.000014 | 
+----------------------+----------+ 

ibdata1中大約是1.5 GB

+0

你可以發佈'SET profiling = 1;/*您的查詢在這裏* /; SHOW個人資料;'。 –

+0

另外,桌子的實際大小是多少?幾MB?或者更多? –

回答

5

一個通用的答案:

  1. 不要使用SELECT *除非你絕對需要的所有列。選擇你只需要的列。
  2. 添加一個ORDER BY子句或LIMIT不會有太大意義。
  3. 創建一個複合(即多列)指數,涵蓋
    • importancecompany_id
    • ORDER BY領域,預期的順序
    • 任何附加字段你想要的SELECT返回(在更換*

這樣數據庫引擎可以通過單一索引查找操作和封面排序以及其他列查找與您的搜索的直接匹配ns直接來自索引。索引包含它涵蓋的所有列的副本;如果所有請求的數據都駐留在索引中,則不需要通過實際表格。這將提高查詢效率。

請注意,這是一個空間速度的交換。添加到索引的每一列都會增加其物理尺寸,因此請明智地選擇。

編輯1:另外,索引對寫操作的速度有影響 - 由於索引維護,INSERT,UPDATE和DELETE查詢會稍微慢一點 - 換而言之,SELECT會更快。 (感謝您的評論,@ Thor84no)

編輯2:如果這個查詢表的主要使用模式表不發生大的變化(!這點很重要),你會考慮創建一個聚集索引。聚集索引表示基表的物理排序,除了基表以外,它不存在,就像其他索引一樣。每當您更改聚集索引的定義或添加/刪除行之間的「現有」記錄時,實際數據都會在物理上重新排序,即在磁盤上執行,這是您想要避免的昂貴操作。

有時候這可能是一個明智的做法,但在你的情況下,它可能不是。如果您的表是某種類型的日誌表,請將聚簇索引保留爲自動遞增標識。

+0

通常,寫入性能的降低比索引佔用的額外光盤空間更大,所以我也會提到這一點。否則很好的答案。 – Thor84no

2

標準select x from y where z(這是你所擁有的,只是有多個條件語句)是可以運行的最有效的查詢之一。你可以真正添加的唯一的東西是一個索引,它包含你正在查詢的所有列;但這會影響寫入此表時的性能。 (以及第一次填充所述指數的高一次命中)。

如果您知道查詢中的某一列會比其他列更限制結果,那麼您可以做出折中並僅在該查詢中添加索引。例如。如果僅查找具有company_id = x的行將確保您只剩下幾行可以過濾掉,那麼只有該列上的索引可能更可取。

1

基本上,由於每個索引只包含WHERE子句中引用的兩個字段之一,所以引擎需要獲取滿足第一部分的記錄和滿足第二部分的記錄(通過使用索引「important」和「FKF49961B13D5FD8EF」)。

索引生成的簡單規則是您希望索引看起來完全像字段在WHERE子句中。因此,您可以按照「重要性」和「company_id」的順序創建索引。這將精確選擇匹配的行,並且不再掃描2.4k行。

+0

這就是我(現在)的,但優化器似乎忽略它 – wjp

+0

然後我的建議是現在使用MySQL的INDEX HINT選項嘗試運行時。 – 0xCAFEBABE

相關問題