【发布时间】:2021-09-24 21:07:53
【问题描述】:
我对 MySQL 5.7 有以下查询,无论我用它做什么,它都在大约一分钟内运行,我试图更快地运行(最好将性能降低到几秒钟)。这些表中的粗略数据量为 200 万条操作、9 万条会话和 10 万条配置文件。
select
a.id as `action_id`,
a.type as `event_type`,
p.ip_address as `ip_address`,
p.browser_string as `browser_string`,
p.ua_device_type,
p.ua_os_family,
p.ua_os_name,
p.ua_type,
p.ua_family,
p.ua_version,
p.ipuas_hash,
s.session_string,
s.traffic_source,
s.org_traffic_source,
a.datetime as `timestamp`
from is_action as a
join is_session as s on a.session_id=s.id
join is_profile as p on s.profile_id=p.id
正在使用下表(删除了一些不相关的字段):
CREATE TABLE `is_profile` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ip_address` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`browser_string` text COLLATE utf8_unicode_ci,
`ua_device_type` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`ua_os_family` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`ua_os_name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`ua_type` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`ua_family` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`ua_version` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`ipuas_hash` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`session_count` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`) USING BTREE,
KEY `user_id` (`user_id`) USING BTREE,
KEY `ua_type` (`ua_type`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
CREATE TABLE `is_session` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`profile_id` int(11) NOT NULL DEFAULT '0',
`traffic_source` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`session_string` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`datetime` datetime DEFAULT NULL,
`session_length` int(11) NOT NULL DEFAULT '0',
`org_traffic_source` mediumtext COLLATE utf8_unicode_ci,
`org_page` mediumtext COLLATE utf8_unicode_ci,
`action_count` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `comp_profile` (`profile_id`,`id`) USING BTREE,
KEY `profile_id` (`profile_id`) USING BTREE,
KEY `datetime` (`datetime`) USING BTREE,
KEY `traffic_source` (`traffic_source`) USING BTREE,
KEY `session_length` (`session_length`) USING BTREE,
CONSTRAINT `fk_profile` FOREIGN KEY (`profile_id`) REFERENCES `is_profile` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
CREATE TABLE `is_action` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`session_id` int(11) NOT NULL,
`type` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`details` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`datetime` datetime NOT NULL,
`weight` int(11) DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `comp_session` (`session_id`,`id`) USING BTREE,
KEY `session_id` (`session_id`) USING BTREE,
KEY `datetime` (`datetime`) USING BTREE,
CONSTRAINT `fk_session` FOREIGN KEY (`session_id`) REFERENCES `is_session` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
我尝试了不同类型的连接、强制索引和在相关字段上添加更多索引,甚至增加了数据库的 RAM 和 CPU,但似乎没有什么能减少查询时间。我还附上了下面EXPLAIN 的屏幕截图(被屏蔽的部分是敏感信息)。
任何帮助将不胜感激。
**编辑:**添加了表之间的外键关系并添加了我忘记添加的EXPLAIN图像。
【问题讨论】:
-
我没有答案,只有观察 - 我们都学习了标准化,它的稳定性,它的一致性。但是,当数据变大时,我们必须退后一步,构建表以匹配查询,并蹑手蹑脚地进入代码必须确保数据一致性的令人担忧的领域。
-
即使数据库在(相当现代的)PC 上运行,这些数据也不是“大”的。假设它在正确指定的服务器上运行,那么它应该毫无困难地处理包含数百万行的 10 甚至 100 行的表
-
观察:在 InnoDB 中,我认为我的说法是正确的,任何 AI id 都会自动静默添加到所有索引的末尾,因此
comp_profile (profile_id,id),KEY profile_id与KEY profile_id相同。 -
您正在返回包含大量列的数以百万计的行。这需要时间。
-
@JSBach - 不完全是。请参阅我的“答案”。
标签: mysql sql performance join