簡體   English   中英

為什么從大表查詢COUNT()比SUM()快得多

[英]Why is COUNT() query from large table much faster than SUM()

我有一個帶有下表的數據倉庫:

主要

約800萬條記錄

CREATE TABLE `main` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`cid` mediumint(8) unsigned DEFAULT NULL, //This is the customer id
`iid` mediumint(8) unsigned DEFAULT NULL, //This is the item id
`pid` tinyint(3) unsigned DEFAULT NULL, //This is the period id
`qty` double DEFAULT NULL,
`sales` double DEFAULT NULL,
`gm` double DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_pci` (`pid`,`cid`,`iid`) USING HASH,
KEY `idx_pic` (`pid`,`iid`,`cid`) USING HASH
) ENGINE=InnoDB AUTO_INCREMENT=7978349 DEFAULT CHARSET=latin1

該表大約有50條記錄,並且具有以下字段

  • ID

顧客

大約有23,000條記錄,以下文件

  • ID
  • 數字//此字段是唯一的
  • name //這只是一個描述字段

以下查詢運行非常快(不到1秒),並返回大約2,000:

select count(*) 
from mydb.main m 
INNER JOIN mydb.period p ON p.id = m.pid 
INNER JOIN mydb.customer c ON c.id = m.cid 
WHERE p.year = 2013 AND c.number = 'ABC';

但是此查詢要慢得多(超過45秒),與前面的查詢相同,但是總和而不是計數:

select sum(sales)
from mydb.main m 
INNER JOIN mydb.period p ON p.id = m.pid 
INNER JOIN mydb.customer c ON c.id = m.cid 
WHERE p.year = 2013 AND c.number = 'ABC';

當我解釋每個查詢時,我唯一看到的區別是在'count()'查詢上,'Extra'字段顯示為'Using index',而對於'sum()'查詢,該字段為NULL。

說明count()查詢

| id | select_type | table | type  | possible_keys        | key          | key_len | ref                 | rows | Extra       |
|  1 | SIMPLE      | c     | const | PRIMARY,idx_customer | idx_customer | 11      | const               |    1 | Using index |
|  1 | SIMPLE      | p     | ref   | PRIMARY,idx_period   | idx_period   | 4       | const               |    6 | Using index |
|  1 | SIMPLE      | m     | ref   | idx_pci,idx_pic      | idx_pci      | 6       | mydb.p.id,const     |    7 | Using index |

解釋sum()查詢

| id | select_type | table | type  | possible_keys        | key          | key_len | ref                 | rows | Extra       |
|  1 | SIMPLE      | c     | const | PRIMARY,idx_customer | idx_customer | 11      | const               |    1 | Using index |
|  1 | SIMPLE      | p     | ref   | PRIMARY,idx_period   | idx_period   | 4       | const               |    6 | Using index |
|  1 | SIMPLE      | m     | ref   | idx_pci,idx_pic      | idx_pci      | 6       | mydb.p.id,const     |    7 | NULL        |
  • 為什么count()比sum()快得多? 它不應該同時使用索引嗎?
  • 我怎樣做才能使sum()更快?

提前致謝!

編輯

所有表都表明它正在使用Engine InnoDB

另外,請注意,如果我只是執行“ SELECT *”查詢,則運行速度非常快(不到2秒)。 我希望'SUM()'不應該花更長的時間,因為SELECT *無論如何都必須檢索行...

解決了

這是我所學到的:

  • 由於sales字段不是索引的一部分,因此它必須從硬盤驅動器中檢索記錄(可能有點慢)。
  • 我對此不太熟悉,但是看起來可以通過切換到SSD(固態驅動器)來提高I / O性能。 我將不得不對此進行更多研究。
  • 現在,我認為我將創建另一層摘要,以便獲得所需的性能。
  • 我將主表上的索引重新定義為(pid,cid,iid,sales,gm,qty),現在sum()查詢的運行速度非常快!

謝謝大家!

索引是鍵行的列表。

當您執行count()查詢時,可以忽略數據庫中的實際數據,而只使用索引。

當您執行sum(sales)查詢時,必須從磁盤讀取每一行以獲取銷售數據,因此要慢得多。

此外,可以批量讀取索引,然后在內存中進行處理,而磁盤訪問將隨機破壞驅動器,以嘗試從磁盤讀取行。

最后,索引本身可能具有計數匯總(以幫助計划生成)

更新

您的表上實際上有三個索引:

PRIMARY KEY (`id`),
KEY `idx_pci` (`pid`,`cid`,`iid`) USING HASH,
KEY `idx_pic` (`pid`,`iid`,`cid`) USING HASH

因此,您僅在idpidcidiid列上具有索引。 (順便說一句,大多數數據庫足夠聰明,可以組合索引,因此您可能可以對索引進行一些優化)

如果您添加了其他鍵(例如KEY idx_sales(id,sales) 可以提高性能,但是鑒於銷售值可能會以數字形式分配,那么您將為更新添加額外的性能成本,這可能是一件壞事

簡單的答案是count()僅對行進行計數。 這可以通過索引來滿足。

sum()需要標識每一行,然后獲取頁面以獲取sales列。 這增加了很多開銷-每行大約加載一頁。

如果將sales添加到索引中,那么它也應該非常快,因為它不必獲取原始數據。

暫無
暫無

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

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