我已经搜索了我可以在 Google、SO 等上搜索的内容,但没有找到似乎适合我正在寻找的答案。我很犹豫要不要就此发表一篇文章,因为我确定答案就在某个地方,我只是找不到它:-\
我已经在 MySQL 中设置了一个表,我真的可以使用一些见解。我有一个现有的索引,它在某些情况下运行良好,而在其他情况下则需要 20 多秒才能运行。让我给你一些背景。
这是一个带有固定行的 MyISAM 表(每列都是一个 INT(11) ),该表目前有 150,000,000 行(总共 10.2 GB)。我用它来跟踪在我们使用的网络软件上运行的分析,因为其他开源替代品(如 Piwik)简直是矫枉过正,我们需要直接访问“东西”。除此之外,还有表格的基本结构。(再次所有 INT(11) ,因为我阅读并理解具有相同类型和长度的索引最有效)。
id region_id location_id action_id visitor_id ts url_id employee_id
Run Code Online (Sandbox Code Playgroud)
这是每列的以下值范围。
150M <20 <3000 <10 <40M unix_time <20k <200k
Run Code Online (Sandbox Code Playgroud)
我尝试运行的查询基本上是获取在特定时间对某个位置执行特定操作的所有访问者的不同计数。(换句话说,查询中必须有位置、动作和 ts)
SELECT COUNT(DISTINCT visitor_id) FROM table WHERE location_id = # AND region_id = # AND action_id = # AND ts BETWEEN x AND y
Run Code Online (Sandbox Code Playgroud)
我有一个关于位置、区域、操作、ts 的多列索引,执行此查询可能需要 20 到 30 秒。我还有另外一个索引,它是简单的visitor_id,ts,我认为它没有显示任何问题,因为visitor_id 具有如此高的基数。EXPLAIN SELECT 显示我正在点击索引,它似乎做得和它所能做的一样好。
id select_type table type possible_keys key key_len ref rows …Run Code Online (Sandbox Code Playgroud) 所以这不是一个关于“如何将表从 latin1 转换为 utf8?”的问题。我完全知道这一点并且明白了。我想问的问题是,“如何才能让这种转变在过渡期间尽可能少地痛苦?” 我知道我需要转换每个表上的列,然后在某个时候将 PHP MySQL 连接从 latin1 更改为 UTF8,如果我的数据库是 1 GB,而不是 1 TB,我可以轻松完成所有这些。
使用 MariaDB 10.3,数据库中有大约 600 个表,全部都在 InnoDB 存储引擎下,我想说其中可能有 50 个在 1GB 以上,大约 20 个在 10 或 100 GB 之间。这大约 20 个表的问题在于它们是应用程序本身的核心,而这 20 个表中的 1 个表是发生大量 UTF8 问题的地方(当前为 66GB)。
因此,处理大约 90% 的表基本上不会有停机时间,但最后 10% 的表就很麻烦了。关于我应该采取什么步骤以及按什么顺序有什么建议吗?我一般的想法是这样的......
有人成功尝试过 Percona 的pt-online-schema-change吗?您认为这对这种情况有帮助吗?
我唯一能想到的另一件事是启动并运行一个新的从属数据库,它是主数据库的新副本,在该从属数据库上进行所有 utf8mb4 更改,然后将从属数据库提升到主数据库。我想我也可以事先转换所有的奴隶,只需在我这样做的时候轮流使用或停止使用它们即可。唯一未知的是如果主设备是 latin1,而从设备都是 utf8mb4,会发生什么情况。所有转换后的数据都很好,但我假设新数据可能是 binlog 中的 latin1 并且与字符集无关?