2017-04-25 51 views
1

我存储在我的数据库的头像,我已经写了应该只是这些照片导出到磁盘的某处一个小C#控制台应用程序时,查询超时。我选择10张照片在一个循环时间:MySQL服务器速度变慢,直到所有选择斑点

const int pageSize = 10; 

using (var connection = new MySqlConnection(_options.Connectionstring)) 
{ 
    connection.Open(); 
    var pageCount = pageSize; 

    for (var page = 0; pageCount == pageSize; page++) 
    { 
     using (var command = new MySqlCommand($"SELECT 
       p.FirstName, p.LastName, p.Department, ph.Data 
      FROM Persons p 
      INNER JOIN Photos ph ON ph.PersonId = p.Id 
      LIMIT {pageSize} OFFSET {page * pageSize}", connection) 
     using (var reader = command.ExecuteReader()) 
     { 
      for (pageCount = 0; reader.Read(); pageCount++) 
      { 
       var path = GetFilePath(reader, _options.Pattern); 
       EnsureDirectoryExists(path); 
       File.WriteAllBytes(path, (byte[])reader["Data"]); 
      } 
     } 
    } 
} 

的代码稍加修改,使之更简洁,但我主要是删除了一些验证和记录。

监视服务器中MySQL工作台而运行的应用程序显示“InnoDB缓冲用法”慢慢蠕动,直到它选择约2分钟或1000个图像之后达到100%。从我读过这是很正常的,但应用程序还出口图像慢,直到InnoDB缓冲得到接近100%,此时应用程序启动超时:

超时过期。操作完成之前超时的时间或服务器没有响应。

数据库服务器信息:

  • MySQL服务器5.6
  • 所有表正使用InnoDB
  • innodb_buffer_pool_size = 1GB
  • 运行Windows Server 2012上使用8 GB RAM

照片表格定义:

CREATE TABLE `Photos` (
    `Id` int(11) NOT NULL AUTO_INCREMENT, 
    `PersonId` int(11) NOT NULL, 
    `Data` longblob NOT NULL, 
    PRIMARY KEY (`Id`), 
    KEY `FK_PersonId_IDX` (`photo_person_id`), 
    CONSTRAINT `FK_PersonId` FOREIGN KEY (`PersonId`) REFERENCES `Persons` (`Id`) 
      ON DELETE CASCADE ON UPDATE CASCADE 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

应用程序本身的内存使用量是非常低的。增加innodb_buffer_pool_size确实增加的时间(导出的照片或数量),直到出现问题,比例尺寸的增加量,但是我不希望有添加更多的内存到服务器只是为了能够导出这些图片。

在我看来,用大块blob填充InnoDB缓冲池导致了这个问题,但从我的理解,如果我确实想要选择所有这些blob,真的没有办法来防止发生这种情况,所以我能做什么?我意识到我可能会增加超时时间,但由于显而易见的原因,这只是一个不好的解决方案,我曾考虑将Photos表更改为MyISAM,我认为这会解决问题,但如果还有其他简单的解决方案,我宁愿不要那样做。如果实际上没有其他办法解决这个问题,我也可以选择完全替代解决方案来输出照片。

我真的不知道还有什么其他的信息是相关的,请让在任何其他细节的意见。

+0

你的代码在哪里?你关闭*连接*吗?处置命令或阅读器不会释放服务器端资源。导出不需要*分页*一次只加载一个记录并将它们写入磁盘。 –

+0

我加了相关的代码,但是你的意思是我不需要分页?我不能一次选择所有的照片......我似乎很奇怪,要关闭每个查询之间的连接,但我想我可以试试它...... – moggizx

+0

将连接的using语句移动到第一个for-循环没有任何区别。 – moggizx

回答

1

不要使用OFFSET,就必须逐步完成所有这些行开始做你真正想要的10。另外,如果正在添加/删除行,则可能会错过或复制一行。

相反remember where you left off

如果由于某种原因,无法实施,那么其中您取刚刚10个IDS,而不是列的其余部分使用“懒EVAL”。这是在一个子查询中。然后JOIN回到表中以获取剩余的所需列。

+0

谢谢,这解决了它! – moggizx