【问题标题】:Performance challenge on MySQL RDS with simultaneous queriesMySQL RDS 上的同时查询性能挑战
【发布时间】:2016-06-26 00:24:51
【问题描述】:

我在 AWS 上通过 NodeJS 开发了一个应用程序,该应用程序具有关联的 MySQL RDS 数据库(服务器类:db.r3.large - 引擎:InnoDB)。我们遇到了性能问题,当我们(同时)执行同时查询时,数据库在完成最后一个查询后返回结果,而不是在每个查询完成后返回结果。

因此,举个例子:如果我们执行一个进程,它有 10 个同时查询,每个查询 3 秒,我们会在大约 30 秒时开始接收结果,并且我们希望在第一个查询完成时(3 秒)开始接收。

似乎数据库正在接收查询并将它们排成队列。

我有点迷路了,因为我更改了代码的几处(单独的连接、池连接等)和 AWS 的设置,但似乎并没有改善结果。

TableA(13M 记录)架构:

CREATE TABLE `TableA` (
  `columnA` int(11) NOT NULL AUTO_INCREMENT,
  `columnB` varchar(20) DEFAULT NULL,
  `columnC` varchar(15) DEFAULT NULL,
  `columnD` varchar(20) DEFAULT NULL,
  `columnE` varchar(255) DEFAULT NULL,
  `columnF` varchar(255) DEFAULT NULL,
  `columnG` varchar(255) DEFAULT NULL,
  `columnH` varchar(10) DEFAULT NULL,
  `columnI` bigint(11) DEFAULT NULL,
  `columnJ` bigint(11) DEFAULT NULL,
  `columnK` varchar(5) DEFAULT NULL,
  `columnL` varchar(50) DEFAULT NULL,
  `columnM` varchar(20) DEFAULT NULL,
  `columnN` int(1) DEFAULT NULL,
  `columnO` int(1) DEFAULT '0',
  `columnP` datetime NOT NULL,
  `columnQ` datetime NOT NULL,
  PRIMARY KEY (`columnA`),
  KEY `columnB` (`columnB`),
  KEY `columnO` (`columnO`),
  KEY `columnK` (`columnK`),
  KEY `columnN` (`columnN`),
  FULLTEXT KEY `columnE` (`columnE`)
) ENGINE=InnoDB AUTO_INCREMENT=13867504 DEFAULT CHARSET=utf8;

TableB(15M 记录)架构:

CREATE TABLE `TableB` (
  `columnA` int(11) NOT NULL AUTO_INCREMENT,
  `columnB` varchar(50) DEFAULT NULL,
  `columnC` varchar(50) DEFAULT NULL,
  `columnD` int(1) DEFAULT NULL,
  `columnE` datetime NOT NULL,
  `columnF` datetime NOT NULL,
  PRIMARY KEY (`columnA`),
  KEY `columnB` (`columnB`),
  KEY `columnC` (`columnC`)
) ENGINE=InnoDB AUTO_INCREMENT=19153275 DEFAULT CHARSET=utf8;

查询:

SELECT COUNT(*) AS total
FROM TableA 
WHERE TableA.columnB IN (  
    SELECT TableB.columnC
    FROM TableB  
    WHERE TableB.columnB = "3764301"  
    AND TableB.columnC NOT IN (   
        SELECT field   
        FROM table   
        WHERE table.field = 10
    AND TableB.columnC NOT IN (    
        SELECT field   
        FROM table   
        WHERE table.field = 10 
    AND TableB.columnC NOT IN (    
        SELECT field   
        FROM table   
        WHERE table.field = 10
    AND TableB.columnC NOT IN (   
        SELECT field   
        FROM table   
        WHERE table.field = 10
)
AND columnM > 2;
  • 2s 1 次执行返回
  • 10 次执行会在 20 秒内返回第一个结果,然后返回另一个结果。

要查看查询是否正在运行,我使用的是“SHOW FULL PROCESSLIST”,并且查询大部分时间都处于“正在发送数据”状态。

这不是查询的性能问题,而是数据库的重复问题。即使是像“SELECT COUNT(*) FROM TableA WHERE columnM = 5”这样非常简单的查询也有同样的问题。

更新

仅出于测试目的,我将查询减少到只有一个子查询条件。两个结果都有 65k 条记录。

-- USING IN
SELECT COUNT(*) as total 
FROM TableA 
WHERE TableA.columnB IN (  
    SELECT TableB.columnC  
       FROM TableB
       WHERE TableB.columnB = "103550181"  
       AND TableB.columnC NOT IN (   
           SELECT field   
           FROM tableX   
           WHERE fieldX = 15  
    )
) 
AND columnM > 2;

-- USING EXISTS
SELECT COUNT(*) as total 
FROM TableA 
WHERE EXISTS (  
    SELECT *  
    FROM TableB  
    WHERE TableB.columnB = "103550181"  
    AND TableA.columnB = TableB.columnC
    AND NOT EXISTS (   
        SELECT *
        FROM tableX
        WHERE fieldX = 15
        AND fieldY = TableB.columnC
   )
) 
AND columnM > 2;

-- Result
Query using IN : 1.7 sec
Query using EXISTS : 141 sec (:O)

使用 IN 或 EXISTS 问题是一样的,当我多次执行此查询时,数据库会出现延迟,并且响应会在很长一段时间后出现。 示例:如果一个查询响应在 1.7 秒内,如果我执行此查询 10 次,第一个结果是在 20 秒内。

【问题讨论】:

  • 您应该考虑至少发布查询和表格概述。没有细节就无法知道。它们中的任何一个都涉及更新吗?您系统的任何其他部分是否在数据库中发生更新?尝试运行SHOW FULL PROCESSLIST 并查看是否有任何查询锁定了行或耗时过长。
  • 谢谢罗德里戈,我在我的问题中添加了更多细节。
  • 运行查询时tx_isolation 是什么?他们在BEGIN...COMMIT 交易中吗?还是使用autocommit=1 运行?
  • 谢谢瑞克。 tx_isolation 是 REPEATABLE-READ 并且自动提交是 1
  • 现在你需要INDEX(fieldX, fieldY)INDEX(columnB, columnC)

标签: mysql node.js amazon-web-services amazon-rds


【解决方案1】:

建议 1

NOT IN ( SELECT ... ) 更改为NOT EXISTS ( SELECT * ... )。 (您可能需要稍微更改WHERE 子句。

AND TableB.columnC NOT IN (    
    SELECT field   
    FROM table   
    WHERE table.field = 10 

-->

AND NOT EXISTS ( SELECT * FROM table WHERE field = TableB.columnC )

table 需要field 上的索引。

IN ( SELECT ... ) 表现很差。 EXISTS 得到了更好的优化。

建议 2

为了处理并发,可以考虑在查询前做SET SESSION TRANSACTION READ UNCOMMITTED。这可能可以防止一个连接干扰另一个连接。

建议 3

向我们展示 EXPLAIN、索引 (SHOW CREATE TABLE)(您提供的还不够)和 WHERE 子句,以便我们对索引进行评论。

建议 4

可能帮助TableB 按此顺序组合INDEX(ColumnB, ColumnC)

【讨论】:

  • 建议1:好的,我试试,但我认为问题出在所有查询上。建议2:什么交易特征?隔离级别,读写还是只读?它是干什么用的?建议 3:我在问题中添加了查询表以获取更多详细信息。提前感谢您的回复
  • 我添加了一些东西。
  • 我已经尝试了您的所有建议,但没有解决重复出现的问题,并且数据库继续延迟 10 倍以上的查询。
  • 请告诉我们查询的最新公式(没有任何IN 子句)。
  • 我觉得我是菜鸟,也许有人能告诉我,表名叫做“table”是某种内部魔法?没有 EXPLAIN 计划,就没有确凿的证据来指出真正的问题。 EXPLAIN 将告诉重复的 IN() 部分被缓存或只是重复任务(这真的很糟糕)
【解决方案2】:

我在这里看到的是正在为每个查询构建巨大的临时表。考虑不同的架构。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-13
    • 1970-01-01
    • 2021-02-10
    • 1970-01-01
    • 1970-01-01
    • 2013-07-18
    相关资源
    最近更新 更多