我的mysql数据库表有问题。我的表中有超过2000万行。表结构如下所示。主要问题是查询需要花费很长时间才能执行(某些查询需要20秒钟以上的时间)。我在可以的地方使用索引,但是许多查询使用日期范围,而在日期范围内我的索引不起作用。同样在查询中,我几乎使用每一列。我需要更改数据表以提高效率吗?
`history` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`barcode` varchar(100) DEFAULT NULL,
`bag` varchar(100) DEFAULT NULL,
`action` int(10) unsigned DEFAULT NULL,
`place` int(10) unsigned DEFAULT NULL,
`price` decimal(10,2) DEFAULT NULL,
`old_price` decimal(10,2) DEFAULT NULL,
`user` int(11) DEFAULT NULL,
`amount` int(10) DEFAULT NULL,
`rotation` int(10) unsigned DEFAULT NULL,
`discount` decimal(10,2) DEFAULT NULL,
`discount_type` tinyint(2) unsigned DEFAULT NULL,
`original` int(10) unsigned DEFAULT NULL,
`was_in_shop` int(10) unsigned DEFAULT NULL,
`cate` int(10) unsigned DEFAULT NULL COMMENT 'grupe',
`sub_cate` int(10) unsigned DEFAULT NULL,
`comment` varchar(255) DEFAULT NULL,
`helper` varchar(255) DEFAULT NULL,
`ywd` varchar(255) DEFAULT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
`deleted_at` timestamp NULL DEFAULT NULL
)
PRIMARY KEY (`id`),
KEY `barcode` (`barcode`) USING BTREE,
KEY `action` (`action`) USING BTREE,
KEY `original` (`original`) USING BTREE,
KEY `created_at` (`created_at`) USING BTREE,
KEY `bag` (`bag`) USING BTREE
ENGINE=InnoDB
我的一些查询
select SUM(amount) as amount,
SUM(comment) as price,
cate
from `history`
where ( `action` = '4'
and `place` = '28'
and `created_at` >= '2018-04-01 00:00:00'
and `created_at` <= '2018-04-30 23:59:59'
)
and `history`.`deleted_at` is null
group by `cate`;
select cate,
SUM(amount) AS kiekis,
SUM(IF(discount>0,(price*amount)-discount,(price*amount))) AS suma,
SUM(IF(discount>0,IF(discount_type=1,(discount*price)/100,discount),0)) AS nuolaida
from `history`
where ( `history`.`action` = '4'
and `history`.`created_at` >= '2018-01-01 00:00:00'
and `history`.`created_at` <= '2018-01-23 23:59:59'
)
and LENGTH(barcode) > 7
and `history`.`deleted_at` is null
group by `cate`;
答案 0 :(得分:1)
您的第一个查询最好写成:
select SUM(h.amount) as amount,
SUM(h.comment) as price,
h.cate
from history h
where h.action = 4 and
h.place = 28 and
h.created_at >= '2018-04-01' and
h.created_at < '2018-05-01' and
h.deleted_at is null
group by h.cate;
为什么?
place
和action
是数字。比较应该是一个数字。混合类型可以防止使用索引。然后,对于此查询,合理的索引为history(action, place, created_at, deleted_at)
。
所以,我将从多列索引开始。
如果仍然遇到性能问题,则应考虑根据created_at
日期对数据进行分区。
答案 1 :(得分:1)
INDEX(a), INDEX(b)
用于某些目的,但是“复合” INDEX(a,b)
更好地用于某些查询。
where ( `action` = '4'
and `place` = '28'
and `created_at` >= '2018-04-01 00:00:00'
and `created_at` <= '2018-04-30 23:59:59'
)
and `history`.`deleted_at` is null
需要
INDEX(action, place, -- first, but in either order
deleted_at,
created_at) -- last
我更喜欢这样写日期范围:
and `history`.`created_at` >= '2018-04-01'
and `history`.`created_at` < '2018-04-01' + INTERVAL 1 MONTH
它比处理leap年,年末等要容易得多。它对于DATE
,DATETIME
,DATETIME(6)
,TIMESTAMP
,和TIMESTAMP(6)
。
为此
where ( `history`.`action` = '4'
and `history`.`created_at` >= '2018-01-01 00:00:00'
and `history`.`created_at` <= '2018-01-23 23:59:59'
)
and LENGTH(barcode) > 7
and `history`.`deleted_at` is null
我将尽可能尝试:
INDEX(action, deleted_at, created_at) -- in this order
不要不在不同的年份使用单独的表格。如果要删除旧数据,请考虑使用PARTITION BY RANGE(TO_DAYS(...))
,以加快DROP PARTITION
的速度。 (但这是另一个讨论。)
答案 2 :(得分:-1)
如果您遇到这种情况,我会考虑使用分页的数据库名称。我的意思是有多个history_X表,其中X是与内容相关的int。
由于这是一个历史记录表,是否可以在名称中包含部分日期?
您说过使用范围来搜索数据,因此如果要在表名中使用年份,则可以
然后,您可以搜索适用于您的日期范围的表。
如果您需要跨越表格范围的日期,则可以使用UNION查询将两个结果集桥接为一个。