mysql创建索引表与1亿行

sczxawaw  于 2023-02-03  发布在  Mysql
关注(0)|答案(3)|浏览(270)

我有几个MySQL表--这些表大约有300列和1亿行。这些表存储日志文件的数据,因此大小也很大。我使用的是InnoDB引擎。涉及这些表的连接的几个查询显然不起作用。我尝试向这些表添加索引,但查询根本无法完成。
我想知道是否有其他方法可以提高性能,或者有什么方法可以让"创建索引"在表上工作?
谢谢你。

qni6mghb

qni6mghb1#

创建一个索引需要时间,与表中的行数成正比。对于一个MySQL表来说,1亿行是相当多的。在该表上创建一个索引可能需要许多小时。确切的时间长短取决于其他因素,包括服务器硬件、要为其创建索引的列的数据类型、数据库上的其他当前负载等。
pt-online-schema-change是一个可以帮助你的工具,它实际上需要更长的时间来建立索引,但是你可以在它工作的时候继续读写原始的表,用一个较小的表来测试,这样你就可以获得一些使用这个工具的经验。
您可以在此处查看有关此工具的网络研讨会:Zero-Downtime Schema Changes in MySQL(免费观看,但需要注册)。
另一种方法是创建一个与原始表类似的空表,在该表中创建索引,然后开始逐步将数据从原始表复制到新表中。如果这是一个日志表,则写入表的次数可能多于读取表的次数,因此您可以立即交换表并立即开始记录新事件,然后随着时间的推移对其进行回填。
pt-archiver这样的工具可以帮助您逐步复制数据,而不会给服务器带来太多的负载。如果您试图在一个事务中复制1亿行,那么简单地执行INSERT INTO... SELECT对数据库服务器的健康没有好处。它还会在原始表上设置锁。pt-archiver的工作原理是一次只复制一小块行。因此它避免了如此大的交易的高成本。
如果使用自动递增主键,请在日志事件开始写入表之前,注意将值调整为高于原始表中的最大值,这样就不会意外地多次标识值。

6gpjuf90

6gpjuf902#

用途

create table newtable like oldtable;

然后在NewTable为空时将索引应用到NewTable。
然后

insert into newtable select * from oldtable;

这也可能需要很长时间才能完成。

xxslljrj

xxslljrj3#

虫子

在使用MyISAM引擎的MySQL表上创建新的辅助索引时会出现一些问题。
MyISAM引擎的一个已知问题是,在一些MySQL版本,如5.7.24(例如Wamp)上,不仅会导致表扫描,而且在创建索引时需要重建整个表。如果您只是删除索引,表也会重建:-(
参考:https://bugs.mysql.com/bug.php?id=93530

备选

有时你不能升级MySQL或者不能要求客户这样做来运行你的解决方案。如果你不需要InnoDB提供的所有功能,将引擎更改为InnoDB可能会导致另一个问题。

索引表

因此,有一种方法是手动创建一个"索引表",这样做的好处是您可以过滤真正需要的记录,正如我在下面解释的:
想象一下,你有一个表上的世界公司的100M记录,其中约30M是美国公司和10M来自加拿大,加上其他公司。
每个公司都有一个COUNTRY和一个STATE字段,您需要对其进行索引,因为您需要按其所在的州搜索美国或加拿大公司。
因此,在MySQL中,如果为Country和State创建索引,那么所有1亿条记录都会被索引,即使是NULL状态。
要解决这个问题,你创建一个索引表和一个真正的索引,如下所示:

create table index_tb_companies (
   company_id int unique,
   company_country char(2),  -- US/CA
   company_state char(2)     -- AL/AK/.../WI/WY
);

create index index_tb_companies_index 
  on index_tb_companies (company_country, company_state);

填充索引表

现在您可以使用简单的insert into或带有过滤后的selectreplace into将原始数据导入索引表。

replace into index_tb_companies(
  company_id, company_country, company_state)
(select 
    company_id, company_country, company_state 
from original_company_table
    where country in ('US', 'CA')
);

这将需要一段时间,因为你可能还没有国家的索引,需要一个完整的表扫描。但最终的索引表大小将低于MySQL索引大小,因为只有美国/加拿大的数据将在那里。

如何选择

现在,最后一部分是利用索引表与您的具体报告的美国和CA公司,因为其他国家不包括在该指数。

select  o.*
from 
    original_company_table o INNER JOIN
    index_tb_companies idx ON idx.company_id = o.company_id
where
    idx.company_country = 'US' 
    and idx.company_state = 'NY'

当您希望索引MySQL上的一小部分数据时,这种方法特别好,因为索引大小很小。

部分索引

其他数据库,如PostgreSQL,有一个"部分索引",你可以创建常规索引,并在创建时传递一个where子句。
PG部分索引:https://www.postgresql.org/docs/8.0/indexes-partial.html
喜欢并分享这个解决方案,如果你从中学习,我正在制作一些关于数据库的材料,并感谢反馈。

相关问题