[英]MySQL query slow (DISTINCT WHERE on indexed column)
眼鏡:
表:
CREATE TABLE `x` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`a` INT(10) UNSIGNED NOT NULL,
`time` DECIMAL(16,6) NOT NULL,
PRIMARY KEY (`id`),
INDEX `a` (`a`),
INDEX `time` (`time`),
INDEX `time_a` (`time`, `a`)
)
COLLATE='utf8_unicode_ci'
ENGINE=InnoDB
AUTO_INCREMENT=298846
;
查詢:
SELECT COUNT(DISTINCT `a`) c
FROM `x`
WHERE `time` >= (UNIX_TIMESTAMP()- (60 * 24));
如果在給定范圍內有很多行且time
,則此查詢非常慢。 還要注意,盡管可能有很多匹配的行(成千上萬或更多),但DISTINCT
a
的數量總是很小(幾百個)。
在以下情況下,無論表的大小如何,查詢都是快速的(基本上是即時的):
time
范圍內只有幾行time
WHERE
部分(因為在索引的a
) 這讓我覺得這是某種無法使用索引上a
計數時,即使EXPLAIN
提到三大股指全部在possibly_keys
。
即使發生以下情況,問題仍然存在:
time
為BIGINT
或DATETIME
類型(對查詢進行了相應的更改) ENGINE=MyISAM
有什么建議么?
SELECT COUNT(DISTINCT `a`)
FROM `x`;
將跳過INDEX(a)
。 請參閱EXPLAIN FORMAT=JSON SELECT ...
然后查找"using_index_for_group_by": true
。 當僅有少量不同的a
值時,這將使其變得非常快。
我懷疑使用WHERE
子句會說"using_index_for_group_by": "scanning"
,這意味着效率較低。 我懷疑實現者是單鍵案例,而不是多鍵案例。
那是整個表格的定義嗎? 我看到沒有任何索引的AUTO_INCREMENT
。 這是怎么回事? 與本討論相關的MyISAM和InnoDB之間的唯一區別是PRIMARY KEY
的處理。
time
的數據類型可能並不重要。
如果我不滿意您的“任何建議?” 問題,請改一下問題。
嘗試使用索引提示來強制查詢使用您要使用的索引。
SELECT COUNT(DISTINCT `a`) c FROM `x` FORCE INDEX (the_index_you_want_to_use) WHERE `time` >= (UNIX_TIMESTAMP()- (60 * 24));
最好不要在where子句中進行任何計算。
var unixtime = UNIX_TIMESTAMP()- (60 * 24)
SELECT COUNT(DISTINCT `a`) c
FROM `x` FORCE INDEX (the_index_you_want_to_use)
WHERE `time` >= unixtime
如果我不得不猜測,問題出在類型上。 UNIX_TIMESTAMP()
返回一個無符號整數。 您的time
變量是decimal
。 這些不是一回事。 而且,類型不匹配會混淆優化器。
聽起來好像表很大,所以更改類型是不可行的(但是,如果可以通過將數據選擇到具有正確類型的新表中,則可能要進行測試)。
以下內容可能會有所幫助:
WHERE `time` >= cast(UNIX_TIMESTAMP() - (60 * 24) as unsigned);
您還可以聲明一個本地無符號變量,並將“常量”存儲在變量中,以查看是否可以解決性能問題。
最后,如果未使用time, a
索引time, a
,請嘗試以下查詢變體:
SELECT COUNT(*) as c
FROM (SELECT DISTINCT a
FROM `x`
WHERE `time` >= CAST(unixtime - 24 * 60 as unsigned)
) ax
我已經看到這種重組提高了其他數據庫的性能,盡管在MySQL上卻沒有。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.