MySQL挂在大型SELECT上
我试图通过连接四个现有表来创建一个新表。我的数据库是静态的,所以制作一个大的预处理表将简化编程,并在将来的查询中节省大量时间。当使用WHERE限制时,我的查询工作正常,但似乎要么挂起,要么走得太慢,没有注意到任何进展 这是工作查询。结果只需要几秒钟MySQL挂在大型SELECT上,mysql,Mysql,我试图通过连接四个现有表来创建一个新表。我的数据库是静态的,所以制作一个大的预处理表将简化编程,并在将来的查询中节省大量时间。当使用WHERE限制时,我的查询工作正常,但似乎要么挂起,要么走得太慢,没有注意到任何进展 这是工作查询。结果只需要几秒钟 SELECT group.group_id, MIN(application.date), person.person_name, pers_appln.sequence FROM group JOIN application ON group.ap
SELECT group.group_id, MIN(application.date), person.person_name, pers_appln.sequence
FROM group
JOIN application ON group.appln_id=application.appln_id
JOIN pers_appln ON pers_appln.appln_id=application.appln_id
JOIN person ON person.person_id=pers_appln.person_id
WHERE group_id="24601"
GROUP BY group.group_id, pers_appln.sequence
;
如果我简单地删除WHERE行,它将运行数天而没有任何显示。在开始时添加一个CREATE TABLE newtable也会做同样的事情。它从不超过0%的进度
组、应用程序和人员表都使用MyISAM引擎,而pers_appln使用InnoDB。所有列都已编制索引。表格大小从大约4000万行到1.5亿行不等。我知道它相当大,但我不认为它会造成这么大的问题。这台计算机目前有4GB的ram
有没有办法让这一切顺利进行
下面是显示创建表信息。没有视图或虚拟表:
CREATE TABLE `group` (
`APPLN_ID` int(10) unsigned NOT NULL,
`GROUP_ID` int(10) unsigned NOT NULL,
KEY `idx_appln` (`APPLN_ID`),
KEY `idx_group` (`GROUP_ID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
CREATE TABLE `application` (
`APPLN_ID` int(10) unsigned NOT NULL,
`APPLN_AUTH` char(2) NOT NULL DEFAULT '',
`APPLN_NR` varchar(20) NOT NULL DEFAULT '',
`APPLN_KIND` char(2) DEFAULT '',
`DATE` date DEFAULT NULL,
`IPR_TYPE` char(2) DEFAULT '',
PRIMARY KEY (`APPLN_ID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
CREATE TABLE `person` (
`PERSON_ID` int(10) unsigned NOT NULL,
`PERSON_CTRY_CODE` char(2) NOT NULL,
`PERSON_NAME` varchar(300) DEFAULT NULL,
`PERSON_ADDRESS` varchar(500) DEFAULT NULL,
KEY `idx_person` (`PERSON_ID`),
) ENGINE=MyISAM DEFAULT CHARSET=utf8 MAX_ROWS=30000000 AVG_ROW_LENGTH=100
CREATE TABLE `pers_appln` (
`PERSON_ID` int(10) unsigned NOT NULL,
`APPLN_ID` int(10) unsigned NOT NULL,
`SEQUENCE` smallint(4) unsigned DEFAULT NULL,
`PLACE` smallint(4) unsigned DEFAULT NULL,
KEY `idx_pers_appln` (`APPLN_ID`),
KEY `idx_person` (`PERSON_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
/*!50100 PARTITION BY HASH (appln_id)
PARTITIONS 20 */
以下是对我的问题的解释:
+----+-------------+-------------+--------+----------------------------+-----------------+---------+--------------------------+----------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------+--------+----------------------------+-----------------+---------+--------------------------+----------+---------------------------------+
| 1 | SIMPLE | person | ALL | idx_person | NULL | NULL | NULL | 47827690 | Using temporary; Using filesort |
| 1 | SIMPLE | pers_appln | ref | idx_application,idx_person | idx_person | 4 | mydb.person.PERSON_ID | 1 | |
| 1 | SIMPLE | application | eq_ref | PRIMARY | PRIMARY | 4 | mydb.pers_appln.APPLN_ID | 1 | |
| 1 | SIMPLE | group | ref | idx_application | idx_application | 4 | mydb.pers_appln.APPLN_ID | 1 | |
+----+-------------+-------------+--------+----------------------------+-----------------+---------+--------------------------+----------+---------------------------------+
验证密钥缓冲池大小约为200M,innodb缓冲池大小约为1200M。也许他们可以更大,但请确保你没有交换 组应具有主键appln_id、组id和索引group_id、appln_id,而不是它具有的两个键 pers_appln应该有INDEXperson_id、appln_id和INDEXappln_id、person_id,而不是它的两个键。如果可能,其中一个应该是主键,但要注意分区 一个小的改进是将那些CHAR2字段更改为字符集ascii-假设您并不真正需要utf8。这会将字段从每行6个字节缩减到2个字节 分区可能根本没有帮助。不,我不能说删除分区会加快速度 如果这些建议没有足够的帮助,请提供解释选择 编辑 转换为InnoDB并为所有表指定主键将有所帮助。这是因为InnoDB将主键与数据聚集在一起。你现在看到的是MyISAM索引和它的数据之间的大量跳跃——实际上是数亿次。假设不是所有东西都可以缓存在小型4GB中,这意味着大量的磁盘I/O。如果非WHERE版本需要一周时间才能运行,我不会感到惊讶。即使使用InnoDB,也会有I/O,但会避免一些I/O,因为: 1.使用PK访问表可以在没有再次命中磁盘的情况下获取数据。 2.我建议的额外索引将避免命中数据,再次避免额外的磁盘命中。 数以百万计的引用*额外的磁盘命中=几天的时间
如果将所有表切换到InnoDB,则应将键缓冲区大小降低到20M,并将InnoDB缓冲区池大小提高到1500M。这些是近似值;请向我们展示使用InnoDB创建表-我想确保每个表都有一个主键,以及哪些列是主键。主键在这种特殊情况下起着很大的作用 对于person,MyISAM版本只有一个KEYperson\u id。如果在转换过程中没有更改密钥,InnoDB将发明一个主键。当连接到该表时,InnoDB将1向下钻取BTree中的键以查找该发明的PK值,然后2向下钻取PK+数据BTree以查找该行。相反,如果person_id可以成为PK,那么该连接的运行速度将是PK的两倍。可能更快,这取决于表有多大以及需要在索引/数据中跳转多少。也就是说,两个BTree查找增加了缓存缓冲池的压力 每张桌子有多大?innodb_buffer_pool_size的最终值是多少?一旦您将所有内容从MyISAM更改为InnoDB,请将key_buffer_size设置为40M或更小,并将InnoDB_buffer_pool_size设置为可用RAM的70%左右。如果所有表的数据+索引大小都小于缓冲池,那么一旦缓存被初始化,查询就不必进行任何I/O操作。这很容易实现10倍的加速 pers_appln是一种多对多关系?那么,可能
PRIMARY KEY(appln_id, person_id),
INDEX(person_id, appln_id) -- if you need to go the other direction, too.
我找到了解决方案:切换到SSD。我的表创建时间从估计的45天增加到16小时。以前,数据库的所有时间都花在硬盘I/O上,几乎不使用5%的CPU或RAM
谢谢大家。您的机器是否有足够的内存来执行此操作?你可能会遇到一堆磁盘操作系统。另外,序列属于哪个表?能否在组id、序列上创建索引?在如此大的表之间创建此叉积将产生一个非常大的中间表。@Barmar叉积是什么意思?@Rachie您需要为查询中的每个表提供EXPLAIN+SHOW create table。联接是表之间的叉积,按ON条件筛选。我更改了密钥缓冲区和池大小
e、 没有效果。我添加了解释选择。有多少百分比的组行的组id=24601?该解释是否反映了?还是没有?WHERE子句?解释中没有WHERE。我只使用WHERE来帮助编写和测试查询。你想得到一个4000万行的结果集吗?不管怎样,这都需要很多时间。我的建议会加快速度,但仍然需要几分钟,也许几个小时。