[英]Optimize query for table with hundreds of millions of rows
這聽起來像是“為我做功課”之類的問題,但是我真的很難解決,試圖使該查詢針對具有許多行的表快速運行。 這是一個顯示模式的SQLFiddle (或多或少)。
我一直在使用索引,試圖獲得可以顯示所有必需列但沒有取得太大成功的東西。 這是create
:
CREATE TABLE `AuditEvent` (
`auditEventId` bigint(20) NOT NULL AUTO_INCREMENT,
`eventTime` datetime NOT NULL,
`target1Id` int(11) DEFAULT NULL,
`target1Name` varchar(100) DEFAULT NULL,
`target2Id` int(11) DEFAULT NULL,
`target2Name` varchar(100) DEFAULT NULL,
`clientId` int(11) NOT NULL DEFAULT '1',
`type` int(11) not null,
PRIMARY KEY (`auditEventId`),
KEY `Transactions` (`clientId`,`eventTime`,`target1Id`,`type`),
KEY `TransactionsJoin` (`auditEventId`, `clientId`,`eventTime`,`target1Id`,`type`)
)
和(一個版本) select
:
select ae.target1Id, ae.type, count(*)
from AuditEvent ae
where ae.clientId=4
and (ae.eventTime between '2011-09-01 03:00:00' and '2012-09-30 23:57:00')
group by ae.target1Id, ae.type;
最后,我還得到了“使用臨時文件”和“使用文件排序”。 我嘗試刪除count(*)
並改為使用select distinct
,這不會導致“使用文件排序”。 如果有一種方法可以重新join
來進行計數,那可能就可以了。
最初,決定跟蹤創建審計記錄時存在的目標的target1Name和target2Name。 我也需要這些名稱(最新名稱)。
當前,查詢(上面,缺少target1Name和target2Name列)在大約2400萬條記錄上運行約5秒鍾。 我們的目標是億萬用戶,我們希望查詢繼續按照這些原則執行(希望將查詢保持在1-2分鍾以內,但我們希望使其更好),但是我擔心的是我們擊中了大量數據(不會進行其他模擬行的工作)。
我不確定獲取更多字段的最佳策略。 如果將列直接添加到select
,則會丟失查詢中的“使用索引”。 我嘗試了join
回表,該表保留了“使用索引”,但大約需要20秒。
我確實嘗試將eventTime列更改為int而不是datetime,但這似乎並未影響索引的使用或時間。
如您所知,這里的問題是ae.eventTime between '2011-09-01 03:00:00' and '2012-09-30 23:57:00'
的范圍條件ae.eventTime between '2011-09-01 03:00:00' and '2012-09-30 23:57:00'
( ae.eventTime between '2011-09-01 03:00:00' and '2012-09-30 23:57:00'
Transactions
索引的使用情況(即索引實際上僅用於clientId
公式和范圍條件的第一部分,並且該索引不用於分組)。
最常見的解決方案是用相等性檢查替換范圍條件(在您的情況下,將一個period
列,將eventTime
到句點中,並將BETWEEN
子句替換為period IN (1,2,3,4,5)
) 。 但這可能會成為您表的開銷。
您可能嘗試的另一種解決方案是添加另一個索引(如果不再使用它,則可能替換Transactions
):( (clientId, target1Id, type, eventTime)
,然后使用以下查詢:
SELECT
ae.target1Id,
ae.type,
COUNT(
NULLIF(ae.eventTime BETWEEN '2011-09-01 03:00:00'
AND '2012-09-30 23:57:00', 0)
) as cnt,
FROM AuditEvent ae
WHERE ae.clientId=4
GROUP BY ae.target1Id, ae.type;
這樣,您將a)將范圍條件移到末尾,b)允許使用索引進行分組,c)使索引成為查詢的覆蓋索引 (即查詢不需要磁盤IO操作)
UPD1:很抱歉,昨天我沒有仔細閱讀您的文章,也沒有注意到您的問題是檢索target1Name
和target2Name
。 首先,我不確定您是否正確理解Using index
的含義。 沒有Using index
並不意味着查詢不Using index
, Using index
意味着索引本身包含足夠的數據來執行子查詢(即索引正在覆蓋)。 由於target1Name
和target2Name
不包含在任何索引中,因此獲取它們的子查詢將沒有Using index
。
如果您只是想知道如何將這兩個字段添加到查詢中(您認為足夠快),請嘗試以下操作:
SELECT a1.target1Id, a1.type, cnt, target1Name, target2Name
FROM (
select ae.target1Id, ae.type, count(*) as cnt, MAX(auditEventId) as max_id
from AuditEvent ae
where ae.clientId=4
and (ae.eventTime between '2011-09-01 03:00:00' and '2012-09-30 23:57:00')
group by ae.target1Id, ae.type) as a1
JOIN AuditEvent a2 ON a1.max_id = a2.auditEventId
;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.