2017-04-25 12 views
1

내 데이터베이스에 프로필 사진을 저장하고 이러한 사진을 어딘가에 디스크로 내보내는 작은 C# 콘솔 앱을 작성했습니다. 나는 루프에서 한 번에 10 사진 선택 : 코드는 약간 더 간결하게 수정blob을 선택할 때 모든 쿼리가 시간 초과 될 때까지 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 Workbench에서 서버를 모니터링하면 약 2 분이 지나면 100 %에 도달하거나 1000 개의 이미지가 선택 될 때까지 "InnoDB 버퍼 사용"이 천천히 올라옵니다. 내가 읽은 바로는 정상이지만, 앱은 InnoDB 버퍼가 100 %에 가까워지면서 앱이 시간 초과되기 시작할 때까지 느리고 느린 이미지를 내 보냅니다.

제한 시간이 만료되었습니다. 작업이 완료되기 전에 시간 초과 기간이 경과되었거나 서버가 응답하지 않습니다.

데이터베이스 서버 정보 :

  • MySQL 서버 5.6
  • 모든 테이블은 윈도우 서버 2012에서 실행
  • innodb_buffer_pool_size = 1기가바이트
  • 이노
  • 을 사용하는 8기가바이트 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를 늘리면 문제가 발생할 때까지 크기가 증가 할 때까지 시간 (또는 사진 수)이 증가하지만이 이미지를 내보낼 수 있도록 서버에 메모리를 추가하지 않아도됩니다. .

InnoDB 버퍼 풀을 large-is blob로 채우는 것은이 문제를 일으키는 것으로 보입니다.하지만이 모든 BLOB를 선택하려는 경우 실제로 발생하지 않도록하는 방법은 없습니다. 내가 무엇을 할 수 있을지? 아마도 타임 아웃을 늘릴 수 있다는 것을 알았지 만 그것은 분명한 이유 때문에 잘못된 해결책 일 뿐이며 Photos 테이블을 MyISAM으로 변경하여 문제를 해결할 것을 고려해 봤지만 다른 쉬운 솔루션이 있다면 그렇게하지 않을 것입니다. . 실제로이 문제를 해결할 다른 방법이 없다면 사진을 내보낼 때 완전히 다른 대안을 찾을 수 있습니다.

기타 정보가 무엇인지 알지 못하므로 다른 세부 정보는 의견에 문의하십시오.

+0

코드는 어디에 있습니까? * 연결 *을 닫습니까? 명령 또는 판독기를 폐기해도 서버 측 자원이 해제되지 않습니다.* 페이징 *은 필요하지 않습니다. 레코드를 한 번에 하나씩로드하고 디스크에 씁니다. –

+0

관련 코드를 추가했지만 페이징이 필요 없다는 것은 무엇을 의미합니까? 한 번에 모든 사진을 선택할 수는 없습니다 ... 또한 모든 쿼리 사이의 연결을 닫는 것이 이상한 것 같지만 시도해 볼 수 있습니다. – moggizx

+0

첫 번째 for- 루프는 아무런 차이가 없었습니다. – moggizx

답변

1

OFFSET을 사용하지 마십시오. 실제로 원하는 10 개까지 모든 행을 거쳐야합니다. 또한 행이 추가/삭제되는 경우 행을 놓치거나 중복 될 수 있습니다.

대신 remember where you left off

당신은 단지 10 개 식별자가 아닌 컬럼의 나머지 부분을 가져 항에있어서, 어떤 이유로, 구현 될 수없는, 그런 다음 "지연 평가"을 사용합니다. 이것은 하위 쿼리에 있습니다. 그런 다음 JOIN을 테이블로 되돌려 원하는 나머지 열을 얻습니다.

+0

고마워,이게 해결 됐어! – moggizx