MariaDB 在使用大型 WHERE IN 时崩溃

Posted

技术标签:

【中文标题】MariaDB 在使用大型 WHERE IN 时崩溃【英文标题】:MariaDB crashes when using large WHERE IN 【发布时间】:2021-02-25 08:49:20 【问题描述】:

我有一个旧项目,我正在尝试升级到新版本的 SQL。它目前正在运行 mysql 5.5,并且运行良好。我已将 som 测试数据迁移到 MariaDB 10.5.9,但是当我尝试运行查询(在 MySql 5.5 上运行良好)时,MariaDB 崩溃。

查询很大,并且广泛使用 WHERE IN。目前我很遗憾无法重构查询,所以我试图找出导致崩溃的原因。

它有 3 个 WHERE IN。第一个是 24 个项目,第二个是 696 个,第三个是 2 个。如果我从第一个或第二个 WHERE IN 中只删除一个项目,它会立即返回数据。 answers 表是MyISAM

我遇到的错误

SQL Error [08S01]: Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.

还有查询

SELECT
    definition_id,
    answer AS value
FROM
    answers
WHERE
    definition_id IN (...)
    AND respondent_id in (...)
    AND context IN (1, 0)
LIMIT 50

我已经尝试将max_allowed_packet 更改为更高的值(在 5.5 中为 16MB),但遗憾的是它没有任何改变。

EXPLAIN SQL_NO_CACHE 的结果(如果我删除了 WHERE IN 中的大量数据以避免崩溃)

id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY ALL 824 Using temporary; Using filesort
2 DERIVED s1 range definition_respondent_context,respondent_id definition_respondent_context 12 824 Using index condition; Using temporary; Using filesort
2 DERIVED s2 eq_ref definition_respondent_context,respondent_id definition_respondent_context 12 const,database_name.s1.respondent_id,const 1

编辑:我设法通过在定义表上使用连接来使其工作

SELECT
    a.definition_id,
    a.answer AS value
FROM
    answers AS a
JOIN definitions AS d ON a.definition_id = d.id
WHERE
    d.id IN (...)
    AND a.respondent_id in (...)
    AND a.context IN (1, 0)
LIMIT 50

【问题讨论】:

附加信息请求。 RAM 大小、# 核心、MySQL 主机服务器上的任何 SSD 或 NVME 设备?在 pastebin.com 上发布并分享链接。从您的 SSH 登录根目录中,文本结果为:B) SHOW GLOBAL STATUS;至少 24 小时正常运行时间后 C) 显示全局变量; D) 显示完整的处理程序;和 可选的非常有用的信息,如果可用,包括 - htop 或 top 用于大多数活动应用程序,ulimit -a 用于 Linux/Unix 限制列表,iostat -xm 5 3 用于按设备和核心/cpu 计数的 IOPS,用于服务器工作负载调整分析提供建议。 请发布 EXPLAIN SELECT SQL_NO_CACHE(您的失败查询);用于分析缺失的索引。 SQL_NO_CACHE 已被弃用一段时间......,请参阅:***.com/questions/58584596/… 此错误在jira.mariadb.org/browse/MDEV-21603 报告,似乎存在于 MariaDB v10.3 及更高版本中,而不是 v10.2。 【参考方案1】:

解决您的问题的一个方法是更改​​您的设计/方法,使您没有包含 500-1000 个项目的 WHERE IN (...) 子句。一方面,您是否会让某些应用程序将如此多的参数传递回您的数据库实例是值得怀疑的。因此,假设这些数据不是来自外部,那么应该可以将其保存在单独的表中。假设您为此有两个表,那么您的查询可能变为:

SELECT a.definition_id, a.answer AS value
FROM answers a
INNER JOIN definitions d
    ON d.id = a.definition_id
INNER JOIN respondents r
    ON r.id = a.respondent_id
WHERE
    context IN (1, 0)
-- ORDER BY <something>
LIMIT 50;

【讨论】:

它是一个遗留代码库,因此到处都需要进行大量更改。在 MySql 5.5 上查询只需要 21 毫秒。所以我的希望是找到一种方法来升级mysql而不必重写整个东西 然后考虑升级到 MySQL 8+,或者最新版本的 MariaDB。我已经给出了我认为最好的长期解决方案作为答案。 我实际上设法让这个工作,只需加入定义表并在其上使用 WHERE IN

以上是关于MariaDB 在使用大型 WHERE IN 时崩溃的主要内容,如果未能解决你的问题,请参考以下文章

honeysql merge-where 构建大型查询

Sequelize - 使用 MariaDB 的 where 子句中的地理位置

如何使用 phpmyadmin 中 10.1.13-MariaDB 中的过程使用 where 子句获取一行

MariaDB 查询使用 IN 和 LIMIT by row

MariaDB收购大型分析公司MammothDB

SQL 性能:使用 order by 时使用 OR 比 IN 慢