簡體   English   中英

如何加快已經在使用索引的count(*)? (MyISAM的)

[英]How can I speed up a count(*) which is already using indexes? (MyISAM)

我有3個大表(10k,10k和100M行),並且試圖對它們的連接進行簡單的計數,其中所有連接的列都已建立索引。 為什么COUNT(*)需要這么長時間,並且我如何加快它(沒有觸發器和運行摘要)?

mysql> describe SELECT COUNT(*) FROM `metaward_alias` INNER JOIN `metaward_achiever` ON (`metaward_alias`.`id` = `metaward_achiever`.`alias_id`) INNER JOIN `metaward_award` ON (`metaward_achiever`.`award_id` = `metaward_award`.`id`) WHERE `metaward_award`.`owner_id` = 8;
+----+-------------+-------------------+--------+-------------------------------------------------------+----------------------------+---------+---------------------------------+------+-------------+
| id | select_type | table             | type   | possible_keys                                         | key                        | key_len | ref                             | rows | Extra       |
+----+-------------+-------------------+--------+-------------------------------------------------------+----------------------------+---------+---------------------------------+------+-------------+
|  1 | SIMPLE      | metaward_award    | ref    | PRIMARY,metaward_award_owner_id                       | metaward_award_owner_id    | 4       | const                           | 1552 |             | 
|  1 | SIMPLE      | metaward_achiever | ref    | metaward_achiever_award_id,metaward_achiever_alias_id | metaward_achiever_award_id | 4       | paul.metaward_award.id          | 2498 |             | 
|  1 | SIMPLE      | metaward_alias    | eq_ref | PRIMARY                                               | PRIMARY                    | 4       | paul.metaward_achiever.alias_id |    1 | Using index | 
+----+-------------+-------------------+--------+-------------------------------------------------------+----------------------------+---------+---------------------------------+------+-------------+
3 rows in set (0.00 sec)

但是實際上運行查詢大約需要10分鍾,而我正在使用MyISAM,因此在此期間表已完全鎖定

我猜想原因是您對三個表進行了巨大的聯接(如果不先應用where子句,結果將是10k * 10k * 100M = 10 16行)。 嘗試重新排序聯接(例如,以metaward_award ,然后僅metaward_achiever了解所需的時間,然后嘗試插入metaward_alias ,可能使用子查詢來強制執行您的首選評估順序)。

如果這樣做沒有幫助,您可能必須對數據進行非規范化,例如,通過存儲特定metaward_achiever的別名數量。 然后,您將完全擺脫一個聯接。 也許您甚至可以緩存metaward_award的總和,具體取決於您的數據更新的頻率和頻率。

可能有幫助的另一件事是將所有數據庫內容都放入RAM :-)

確保您具有以下指標:

metaward_alias      id
metaward_achiever   alias_id
metaward_achiever   award_id
metaward_award      id
metaward_award      owner_id

我敢肯定,很多人也會建議指望特定的列,但是在MySql中,這對您的查詢沒有任何影響。

更新

您也可以嘗試在主表而不是已連接表之一上設置條件。 那會給你同樣的結果,但是可能更快(我不知道MySql有多聰明):

SELECT COUNT(*) FROM `metaward_award` 
   INNER JOIN `metaward_achiever` 
      ON (`metaward_achiever`.`award_id` = `metaward_award`.`id`) 
   INNER JOIN `metaward_alias` 
      ON (`metaward_alias`.`id` = `metaward_achiever`.`alias_id`) 
WHERE `metaward_award`.`owner_id` = 8

10分鍾對於該查詢來說太長了。 我認為您必須擁有非常小的密鑰緩存。 您可以通過以下方式獲取其大小(以字節為單位):

SELECT @@key_buffer_size

首先,您應該運行ANALYZE TABLEOPTIMIZE TABLE 他們將對您的索引進行排序,並可以稍微改善性能。

您還應該查看是否可以對列使用更緊湊的類型。 例如,如果您的所有者,獎勵或別名不超過1600萬,則可以將INT列更改為MEDIUMINT(當然是UNSIGNED)。 在某些情況下甚至可能是SMALLINT? 這樣可以減少索引占用量,並將更多的索引放入緩存中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM