Din*_*esh 7 mysql mysql-5 performance optimization mysql-5.5 query-performance
我有一个包含 600,000 条记录的交易表,我需要在财政年度的基础上列出仪表板的计数。使用的表是 MyISAM。我尝试为交易日期 ( tran_date
)添加索引。即使它正在使用索引,它也会创建临时表,由于临时表和文件排序需要更多时间。有什么办法可以优化查询以提高查询时间?
SELECT COUNT( * ) AS cnt, CASE WHEN MONTH( tran_date ) >=3 THEN concat( YEAR( tran_date ) , '-', YEAR( tran_date ) +1 ) ELSE concat( YEAR( tran_date ) -1, '-', YEAR( tran_date ) ) END AS 财务年 从`交易1` WHERE tran_date >= '2010-06-01' 按财务年分组 显示第 0 - 4 行(共 5 行,查询耗时 1.2095 秒)
id select_type table type possible_keys key key_len ref rows Extra 1 简单交易 1 范围 PRIMARY,tran_date tran_date 8 NULL 346485 使用 where; 使用索引;使用临时;使用文件排序
键名类型唯一打包字段基数排序规则 PRIMARY BTREE 是 否 tran_date 205720 A tran_ID 617162 A 优惠券_否 BTREE 否 优惠券_否 617162 A account_typeBTREE 否 否 account_type 3 A prodCode BTREE 否 否 prodCode 430 A tran_date 308581 A tran_date BTREE 否 否 tran_date 205720 A cust_ID BTREE 否 否 cust_ID 3265 A tran_date 308581 A account_type 308581 A 点数 617162 A
更新 :
尝试添加分区,与未分区的分区相比,这没有多大帮助。在这种情况下,复制是否有助于阅读此表?。读取数据时,会根据日期(使用日期函数)进行更多分组。
编辑:
我更改了查询并减少了查询执行时间。我使用的查询是,
选择总和(计数) 从 ( SELECT COUNT( * ) 作为计数, MONTH( tran_date ) >=3 时的情况 THEN concat( YEAR( tran_date ) , '-', YEAR( tran_date ) +1 ) ELSE concat( YEAR( tran_date ) -1, '-', YEAR( tran_date ) ) END AS format_date FROM 交易 1 GROUP BY tran_date ) AS GROUP BY format_date 显示第 0 - 4 行(共 5 行,查询耗时 0.5636 秒)
id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY <derived2> ALL NULL NULL NULL NULL 229676 使用临时;使用文件排序 2 DERIVED transactions1 index NULL tran_date 8 NULL 617162 使用索引
但是当使用
SELECT COUNT( * ) 作为计数, MONTH( tran_date ) >=3 时的情况 THEN concat( YEAR( tran_date ) , '-', YEAR( tran_date ) +1 ) ELSE concat( YEAR( tran_date ) -1, '-', YEAR( tran_date ) ) END AS format_date FROM 交易 1 GROUP BY tran_date 显示第 0 - 29 行(总共 229,676 行,查询耗时 0.0006 秒)
如果不使用SUM(count)
派生表中的,则时间更少。有没有其他方法可以在不使用 MySQL 中的子查询的情况下获得总和,或者可以优化子查询以获取索引。
我看不到太多改进的机会。
您添加的索引可能有很大帮助,因为它用于 WHERE 子句的范围匹配(type => range,key => tran_date),并且它被用作覆盖索引(extra => using index),避免需要查找表来获取行数据。
但由于您使用函数来构造分组依据的 Financial_year 值,因此“使用文件排序”和“使用临时”都无法避免。但是,这些并不是真正的问题。真正的问题是,您对 MONTH(tran_date) 进行了 346,485 次评估,而 YEAR(tran_date) 至少评估了那么多次......一秒钟内大约 700,000 次函数调用似乎还不错。
计划 B:我绝对不喜欢存储冗余数据,并且我坚决反对让应用程序负责维护它......但我可能会尝试的一个选择是创建一个仪表板统计数据按金融年表,并且在 transactions1 表上使用插入/更新/删除后触发器来管理保持这些统计信息最新。
当然,这个选项是有成本的——增加了更新/插入/删除交易所需的时间……但是,等待超过 1200 毫秒的仪表板统计数据也是一种成本。因此,这可能取决于您是想现在付款还是稍后付款。