1

首先,这是我的查询:

SELECT 
    COUNT(*) as velocity_count, 
    SUM(`disbursements`.`amount`) as summation_amount 
FROM `disbursements` 
WHERE 
    `disbursements`.`accumulation_hash` = '40ad7f250cf23919bd8cc4619850a40444c5e90c978f88635a09ccf66a82ffb38e39ea51cdfd651b0ebdac5f5ca37cd7a17e0f60fea6cbce1397ccff5fa37346' 
    AND `disbursements`.`caller_id` = 1 
    AND `disbursements`.`active` = 1 
    AND (version_hash != '86b4111677294b27a1805643d193b8d437b6ddb170b4ed5dec39aa89bf070d160cbbcd697dfc1988efea8429b1f1557625bf956180c65d3dcd3a318280e0d2da') 
    AND (`disbursements`.`created_at` BETWEEN '2012-12-15 23:33:22' 
    AND '2013-01-14 23:33:22') LIMIT 1

解释扩展返回如下:

+----+-------------+---------------+-------+-----------------------------------------------------------------------------------------------------------------------------------------------+------------------------------+---------+------+--------+----------+--------------------------+
| id | select_type | table         | type  | possible_keys                                                                                                                                 | key                          | key_len | ref  | rows   | filtered | Extra                    |
+----+-------------+---------------+-------+-----------------------------------------------------------------------------------------------------------------------------------------------+------------------------------+---------+------+--------+----------+--------------------------+
|  1 | SIMPLE      | disbursements | range | unique_request_index,index_disbursements_on_caller_id,disbursement_summation_index,disbursement_velocity_index,disbursement_version_out_index | disbursement_summation_index | 1543    | NULL | 191422 |   100.00 | Using where; Using index |
+----+-------------+---------------+-------+-----------------------------------------------------------------------------------------------------------------------------------------------+------------------------------+---------+------+--------+----------+--------------------------+

实际查询大约有 95,000 行。如果我解释另一个命中约 50 行的查询,则解释是相同的,只是估计的行数更少。

选择的索引按顺序包括累积哈希、调用者 ID、活动、版本哈希、创建时间、金额。

我尝试过使用 COUNT(id) 或 COUNT(caller_id),因为它们是非空字段并返回与 count(*) 相同的内容,但它对计划或运行时间没有任何影响的实际查询。

这也是一个很重的插入表,基本上每个查询自上次运行以来都会插入或更新一行,因此 mysql 查询缓存并不完全有用。

在我去使用 memcache 或 redis 之类的东西制作某种分桶时间序列缓存之前,是否有一个明显的解决方案可以让它更快地工作?正常的约 50 行查询在 5MS 内返回,超过 90k+ 行的查询需要 500-900MS,而我真的负担不起超过 100MS 的任何东西。

我应该指出日期是一个滚动的 30 天窗口,需要基本上是实时的。过期可能会以大约 1 分钟的粒度发生,但新项目需要在提交后立即看到。我也在RDS上,读取IOPS基本上是0,cpu大概是60-80%。当我不查询庞大的 90,000 多个记录项时,CPU 通常保持在 10% 以下。

4

1 回答 1

0

您可以尝试created_at以前的索引version_hash(可能会更好地进行索引范围扫描...不清楚该非相等谓词如何version_hash影响计划,但我怀疑它会禁用created_at列上的范围扫描。

除此之外,查询和索引看起来和您将要获得的一样好,EXPLAIN 输出显示查询正在从索引中得到满足。

考虑到它聚合了 95,000 多行,尤其是考虑到 1543 字节的密钥长度,该语句的性能听起来并不太合理。这比我通常处理的要大得多。

索引中列的数据类型是什么,簇键或主键是什么?

accumulation_hash - 128-character representation of 512-bit value
caller_id - integer or numeric (?)
active - integer or numeric (?)
version_hash - another 128-characters
created_at - datetime (8bytes) or timestamp (4bytes)
amount - numeric or integer 

95,000 行,每行 1543 字节,数据量约为 140MB。

于 2013-01-15T00:27:11.853 回答