SharePoint 데이터베이스로 부터 모든 문서를 백업 및 추출하기

개요

필자는 SharePoint 서버 제품을 이용해서 문서를 관리해 왔다. SharePoint를 이용하면 수 천개의 문서를 종류별로 분류하고 데이터베이스화할 수 있다. 문서의 종류와 문서의 내용도 인덱싱(indexing)되므로 문서 내용과 다양한 메타 데이터로 문서를 검색할 수 있다는 점 때문에 많은 문서를 쉽게 관리하고 검색할 수 있다는 장점이 있다.

SharePoint의 장점을 나열하지면 많겠지만, 모바일 트랜드 시대에서는 에버노트가 최고이지 쉽다. 필자의 에버노트와 DropBox는 땡전 한푼 안들이고 프리미엄 서비스를 받고 있는데, 필자가 문서를 사용하고 관리하는 패턴에선 SharePoint 보다는 에버노트DropBox 조합이 더 접근성이 좋고 사용하기도 편하다. 데스크탑은 물론이고 브라우저, 다양한 모바일 기기에서 에버노트 클리핑과 DropBox 동기화 등을 지원하기 때문이다.

그래서 이번에 필자가 가지고 있는 수 천개의 모든 문서를 이전하고자 SharePoint의 모든 파일을 추출해야 했다. 여기에서 여러 Site Collections/Sites/Doc Libs의 각각의 문서를 한 번에 추출하는 작업을 진행했다.

1. WSS_Content 데이터베이스 연결

원하는 툴을 이용해서 SharePoint가 사용하는 데이터베이스에 연결한다. SharePoint에 저장된 문서가 많을 수록 데이터베이스에 연결해야 하는 시간이 늘어난다. 그러므로 Timeout이 발생하지 않도록 주의해야 한다. 필자는 여기에서 SSMS(Sql Server Management Studio) 2012 버전을 사용했다.

2. 파일 추출하기

2.1. 데이터베이스 구성 변경 쿼리 실행

sp_configure 'show advanced options', 1;  
GO

RECONFIGURE;  
GO

sp_configure 'Ole Automation Procedures', 1;  
GO

RECONFIGURE;  
GO

2.2. 데이터베이스 추출 쿼리 실행

아래의 쿼리는 이 사이트의 링크[1]를 참고하였으나, 일부 오류가 발생하여 필자가 수정한 부분이 있으니 이점 참고하기 바란다.

그리고 SharePoint에 저장되는 파일들은 다양한 타입이 존재한다. 가령, 메타데이터의 Binary 파일, _private 폴더, *.aspx, 시스템에 필요한 파일 등 필자가 저장한 문서와 상관 없는 찌꺼기 들도 함께 저장이 된다.

파일의 다양한 플래그 값은 MSDN의 Document Store Type, Doc Flags 문서[2]를 참고 하면 된다.


  
[그림1] WSS_Content 데이터베이스의 모든 문서를 파일 시스템으로 추출한 결과 화면


USE WSS_CONTENT;  

DECLARE @PATH_PREFIX  NVARCHAR(1024);  
SET @PATH_PREFIX = 'C:\BACKUP\';  -- 이곳에 백업할 경로를 입력, 반드시 뒤에 '\' 문자 추가하셈'


--DECLARING THE CURSOR, THIS IS THE ITEMS YOU WANT TO RUN THE EXTRACTING ON  
DECLARE CURSOR_Images CURSOR FOR (SELECT Id FROM [dbo].[AllDocs])  

--DECLARE THE TYPE OF THE COLUMN YOU SELECTED ABOVE  
DECLARE @ImageID uniqueidentifier;  

--START THE CURSOR AND RUN THROUGH ALL THE ITEMS IN CURSOR_Images  
OPEN CURSOR_Images  
FETCH NEXT FROM CURSOR_Images INTO @ImageID  
WHILE (@@FETCH_STATUS <> -1)  
BEGIN  
  --DECLARE THE VARIABLE THAT WILL KEEP THE BINARY DATA  
  DECLARE @ImageData varbinary(MAX);  
  --SELECT THE BINARY DATA AND SET IT TO @ImageData.  THE BINARY DATA FOR ALLDOCS ARE LOCATED IN ALLDOCSTREAMS  
  --AND THE ID IS THE SAME AS IN ALLDOCS  
  SELECT @ImageData = (SELECT TOP 1 CONVERT(varbinary(MAX), Content, 1) FROM [dbo].[AllDocStreams] WHERE Id = @ImageID ORDER BY InternalVersion ASC);

  --GET THE LOCATION OF THE DIRECTORY THE FILES WAS SAVED IN AND CHANGE REPLACE THE / WITH \ TO BE USED IN FILESYSTEM  
  DECLARE @DIRPATH NVARCHAR(MAX);  
  SET @DIRPATH = REPLACE((SELECT  DirName FROM [dbo].[AllDocs]  WHERE Id = @ImageID),'/','\');

  --SET THE PATH  
  DECLARE @Path nvarchar(1024);  
  --SELECT @Path = 'C:\Export\' + @DIRPATH + '\';  
  SELECT @Path = @PATH_PREFIX + @DIRPATH + '\';
-- '\

  --CREATE THE DIRECTORIES  
  EXEC master.dbo.xp_create_subdir @Path;

  --GET THE FILE NAME OF THE FILE FROM LEAFNAME  
  DECLARE @Filename NVARCHAR(1024);  
  DECLARE @DocFlags INT;  
  DECLARE @Type     TINYINT;  
  SELECT @Filename = (SELECT LeafName FROM [dbo].[AllDocs] WHERE id = @ImageID);  
  SELECT @DocFlags = (SELECT DocFlags FROM [dbo].[AllDocs] WHERE id = @ImageID);  
  SELECT @Type     = (SELECT [Type]    FROM [dbo].[AllDocs] WHERE id = @ImageID);

  -- 폴더를 0바이트 파일로 생성하므로 파일이 아닌 경우 파일 저장 루틴 진입 금지  
  IF (@Type = 1 AND @DocFlags = 0) OR (@DocFlags & 0x100) <> 0x100 BEGIN  
CONTINUE;  
  END   
  ELSE BEGIN

  --SET THE FULL PATH FOR WHERE THE FILES WILL BE STORED  
  DECLARE @FullPathToOutputFile NVARCHAR(2048);  
  SELECT @FullPathToOutputFile = @Path + '\' + @Filename;

  --SAVE THE FILE TO THE FILE SYSTEM  -'
  DECLARE @ObjectToken INT  
  EXEC sp_OACreate 'ADODB.Stream', @ObjectToken OUTPUT;  
  EXEC sp_OASetProperty @ObjectToken, 'TYPE', 1;  
  EXEC sp_OAMethod @ObjectToken, 'OPEN';  
  EXEC sp_OAMethod @ObjectToken, 'WRITE', NULL, @ImageData;  
  EXEC sp_OAMethod @ObjectToken, 'SaveToFile', NULL, @FullPathToOutputFile, 2;  
  EXEC sp_OAMethod @ObjectToken, 'Close';  
  EXEC sp_OADestroy @ObjectToken;

  END

  --LOOP TO THE NEXT ENTRY IN THE CURSOR  
  FETCH NEXT FROM CURSOR_Images INTO @ImageID  
END  
CLOSE CURSOR_Images  
DEALLOCATE CURSOR_Images  

2.3. 참고 사항

위의 쿼리는 다양한 메타데이터와 시스템 파일(*.aspx, _private 등..)을 모두 저장한다. 이런 쓰레기 데이터를 파일로 저장하지 않길 원한다면 아래의 쿼리를 이용해서 조건절을 추가해 주면 된다.

각각의 플래그 값의 의미는 Document Store Type 문서를 참고하면 된다. 그러면 여러분이 원하는 데이터만 파일 시스템으로 추출하여 저장하도록 커스터마이징이 될 것이다.

SELECT LeafName, DocFlags  
  FROM [dbo].[AllDocs]  
 WHERE (DocFlags & 0x100) = 0x100
   AND (DocFlags & 0xFFFF0000) <> 0xFFFF0000
   AND (DocFlags & 0x80) <> 0x80
   AND (DocFlags & 0x10) <> 0x10
   AND (DocFlags & 0x8) <> 0x8  

결론

만약 SharePoint에 저장되었던 많은 파일 또는 데이터를 전혀 다른 솔루션으로 이전하고 싶은 경우가 있다. SharePoint는 Microsft SQL Server 데이터베이스에 바이너리를 저장하는데 파일 시스템을 단일 데이터베이스에 저장한다는 것이 좀 아이러니 한 구조이다.

많은 기업내 담당자들의 SharePoint에 대한 피드백을 물어보면 빠지지 않는 것은 ‘느리다’ 라는 것인데, 기하급수적으로 늘어나는 데이터베이스 용량과 웹 응용 프로그램의 SPSites/DocLibs 등이 생성되면서 시간이 지날 수록 점점 느려지는 것은 어쩔 수 없는 구조인 듯 하다. 더불어 SharePoint는 과거의 아키텍처가 현재까지도 트랜드의 변화에 대응되지 못하고 전반적으로 과거와 동일한 아키텍처에 새로운 기능만 계속 붙여나가다 보니 솔루션 자체의 구조적인 면에서 악순환이 되풀이 되는 형세이다.

하지만, 이 아티클을 통해 SharePoint 데이터베이스에서 직접 파일을 추출하여 파일 시스템으로 저장할 수 있다. 이 방법을 통해 추출된 다량의 파일을 다른 솔루션으로 옮기거나 업로드하면 끝이다.


Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. 억사마 2014.02.03 18:00 신고 Address Modify/Delete Reply

    안녕하세요~ 연락처가 어디 없으셔서 이렇게 댓글 남깁니다. SharePoint를 파일시스템에 백업을 받아야하는 급박한 회사업무가 생겼습니다. 좀 도움을 얻을수 있을까요? 부탁드리겠습니다. 혹시 몰라 제 이메일 주소를 남깁니다. e.joe@samsung.com 연락 부탁드리겠습니다. 감사합니다.

  2. 2014.02.03 18:14 Address Modify/Delete Reply

    비밀댓글입니다

JS-Lambda 자바스크립트 라이브러리를 공개합니다.


JavaScript Array Extensions 자바스크립트 오픈 소스를 개발한 데 이어 JS-LambdaLGPL 라이센스로 공개합니다.

JavaScript 에서 람다 표현식(Lambda Expression)을 사용할 수 있도록 만든 라이브러리 입니다. 자세한 내용은 아래의 소스 코드를 참고 하시면 됩니다.

Github: https://github.com/powerumc/js-lambda

JS Lambda

  • It is possible lambda expression that can be used JavaScript.
  • you just got a function F();

Simple Examples

// Before  
function func(a,b) {
    return a + b;
}  
console.info( func(4,6) );


// ** After with JS-Lambda **  
var func = F("a,b => a + b");  
console.info( func(4,6) );  

// Result  
10

Or you can invoke directly

// Before  
function anonymousMethod(a,b) {
    return a + b;
}  
console.info( anonymousMethod(4,6) );  

// ** After with JS-Lambda **  
console.info( F("a,b => a + b")(4,6) );  

// Result  
10

Callback Examples

// Before  
function callback( func ) {
    if( func ) func();
}  

callback( function() { console.info('My name is Junil Um'); } );  

// ** After with JS-Lambda **  
callback(  F("() => console.info('My name is Junil Um');")  );  

// Result  
My name is Junil Um  

With jQuery

// Before  
var li = $("item li");  

li.each( function(i, o) {
    $(o).addClass("some");
} );


// ** After with JS-Lambda **  
var li = $("item li");  

li.each( F("(i, o) => $(o).addClass('some');") );  


Posted by 땡초 POWERUMC

댓글을 달아 주세요


최근 Git이나 Mercurial 과 같은 분산제어 방식의 소스 제어 제품을 무조건 맹신하고 찬양하거나 분산제어 방식보다 중앙집중형 소스제어 방식을 무조건 배척하는 현상이 일부 나타나고 있다.

리누스 토발즈(Linus Tovalds)와 같은 공산주의(Communism) 사상의 이상을 강조하는 철학이 담긴 Git은 GitHub.com을 통해 소스 코드를 공유함으로서 오픈 소스 진영에 매우 발전적인 기여를 하고 있음은 확실하다. 리누스 토발즈(Linus Tovalds)가 만든 것이라 그런지 훨씬 더 주목받고 있는 것 같다.

중앙집중 소스제어와 분산제어 소스제어 방식은 그 원칙과 근본적인 가치에 차이가 있는, 방법론으로 접근해야 할 것이다. 따라서 각 소스 제어의 방식마다 특징과 장단점이 있으며 ‘좋은 게 좋은 것 아닌가~’ 라는 간단한 답을 얻길 바란다.

필자는 중앙집중 소스제어와 분산제어 소스제어 방식의 장단점을 5가지의 관점에서 살펴보자. 중앙집중 소스제어(이하 중앙제어 방식)은 분산제어 소스제어 방식을 사용하는 몇 가지 소프트웨어를 제외한 대부분으로 보면 된다.

  • 중앙통제력
  • 정책주입력
  • 분기용이성
  • 사용편의성
  • 성능

그 외에 도움이 될만한 위키피디아(Wikipedia) 링크를 참고하기 바란다.

내용상 비교하는 대상은 중앙제어 방식은 ‘팀 파운데이션 서버(Team Foundation Server)’와 SVN을 많이 참조하였고, 분산제어 방식은 ‘Git’을 많이 참조하였다.

중립적인 관점에서 글을 작성하였으나 어느 한 쪽으로 편향이 되었다면 미리 그 점에 대해 양해를 구하는 바이다.

중앙통제력

이름에서도 알 수 있는 것 처럼 중앙집중적인 통제력은 기존의 중앙집중 방식이 분산제어 방식보다 유리한 점이 많다. 분산제어 방식은 자신이 서버로의 통제를 받는 동시에 제 3자에게 있어 자기 자신이 서버가 된다. 반면, 중앙집중 방식에서는 서버가 오직 물리적인 한 곳에 위치해 있다.

때문에 중앙집중 방식은 조직에 있어 정책적인 부분을 클라이언트에게 강제로 주입할 수 있는 여지가 많다. (물론 분산제어 방식도 가능하다) 중앙 서버 한 곳의 설정만으로 많은 클라이언트를 통제할 수 있다.


이미지 참조

그리고 모든 히스토리는 중앙 서버의 데이터베이스에 저장이 되기 때문에 클라이언트에게는 단지 소스 밖에 없지만, 분산제어 방식은 그렇지가 않다. Git의 스테이징 스토리지가 바로 클라이언트가 가지고 있는 데이터를 저장하는 (임시?)스토리지다.

조직에서 소스코드가 변경되는 주요 변경 이력은 매우 민감한 부분이고, 영업비밀과 직결되는 요소들이 많다. 응용프로그램이 연결되는 데이터베이스의 컬럼이나 테이블의 사소한 변경에도 응용프로그램은 수정되어야 할 수 있고, 이것이 응용프로그램의 소스코드에 반영이 되면서 소스제어에 이력을 남기게 된다.

정책주입력

정책적인 주입력은 중앙통제력과 유사한 부분이 많다. 중앙통제력이 크면 클수록 정책주임력은 향상된다. 중앙 서버의 정책적인 설정만으로 여러 클라이언트는 중앙 서버에 의해 통제받을 수 있다.

특히 ALM(Application Lifecycle Mamangement) 제품과 개발 IDE 제품간에 얼마나 긴밀하게 잘 통합이 되었느냐에 따라 정책주입력에 영향을 미친다. 통합이란 것이 양날의 검과 같아서 좋게 말하면 ‘All in One’이라 표현할 수 있겠고, 나쁘게 말하면 구성요소간에 강한 응집력으로 인해 제한된 확장이라 말할 수 있겠다.

ALM 통합의 장점

  1. 한 번의 구성으로 모든 것을 사용할 수 있다.
  2. 새로운 업그레이드도 한 번의 구성으로 모든 것을 구성할 수 있다.
  3. 개발툴과 통합되어 사용하기 쉽다.

ALM 통합의 단점

  1. 설치/구성 환경은 벤더에 의해 결정된다.
  2. 기능이 하나 하나가 완성도가 높지 않아 기업 및 도메인 환경에서는 추가 개발이 필요한 경우가 많다. (범용성을 위해…)
  3. 오픈 소스 ALM 도구보다 쓸 수 있는 도구들이 적다. (애드인/플러그인)
  4. 다양한 외부 도구와 연동이 제한된다.

분기용이성

분기(Branch)는 나무에서 여러 가지(Branch)로 뻗어 나가는 것을 일컬어, 하나의 소스 코드에서 여러 가지(Branch)로 소스 코드를 키울 수 있다. 특히 분산 제어 방식에서 분기가 얼마나 유용하고 효율적으로 사용할 수 있는지 잘 알 수 있다.

중앙 제어 방식에서의 분기는 곧 변경 이력으로 반영되어 영구적으로 분기 이력이 남게 된다. 때문에, 분기를 개인적인 용도로 사용하는 것이 힘들다. 소스 제어의 파일 시스템 구조를 복잡하게 만들 수 있고 구성원 개개인이 이를 핸들링 하기에는 전체 제품의 소스 코드에 좋지 않은 영향을 미칠 수 있다.


이미지 참조

반면, 분산 제어 방식의 경우 분기는 반드시 알아야 할 매우 효과적인 기능 중 하나로 볼 수 있다. 위에서 언급 했듯이 서버에게는 클라이언트가 되지만, 제 3자에게는 곧 서버가 된다. 즉, 로컬 서버(클라이언트)에서 자체적으로 분기가 가능해진다. 클라이언트에서 분기와 서버로 Push되는 정보는 다르므로 서버의 정책이나 구조에 영향을 최소한으로 적게 미치게 된다.

하지만, 중앙 제어 방식에서도 이런 단점은 충분히 극복할 수 있다. 분기는 병합(Merge)이라는 조건을 전제로 수행되는데, 만약 병합이라는 전제 조건이 없다는 가정하에 이와 유사하게 문제를 해결할 수 있는 방법이 있다.

중앙 집중 방식의 소스 제어 제품마다 기능적으로 다른 점이 있겠지만, 다중 작업 영역(Workspace) 또는 보류(Shelve) 기능을 이용하여 로컬 분기(Local Branch) 기능을 유사하게 흉내낼 수 있다. (물론 진정한 의미에서의 분기 목적과는 다소 차이가 있다)

사용편의성

사용편의성은 소스 제어를 사용하는 사용자가 얼마나 소스 제어를 편하게 사용함을 의미한다. 이를 언급하기 전에 사용편의성은 개개인의 경험적인 부분에서 다를 수 있다.

먼저, 분산제어 방식의 대표적인 Git을 험오하는 이유 10가지에 대해 쓴 블로그 내용을 참고하자.

Git is the source code version control system that is rapidly becoming the standard for open source projects. It has a powerful distributed model which allows advanced users to do tricky things with branches, and rewriting history. What a pity that it’s so hard to learn, has such an unpleasant command line interface, and treats its users with such utter contempt.
이하 생략…
http://steveko.wordpress.com/2012/02/24/10-things-i-hate-about-git/

대부분의 소스 제어 명령은 GUI(그래픽 인터페이스)와 CMD(명령줄 인터페이스) 방식을 제공한다. 주로 GUI 방식은 개발툴과 연동이 되는 확장 또는 플러그인 방식으로 제공되고, CMD 방식은 소스 제어 제품 자체에서 제공하는 고유의 기능으로 제공이 되는 것이 대부분이다. 그래서 소스 제어를 사용하는 개발자가 어떤 환경에서 개발하느냐에 따라 GUI 또는 CMD 방식으로 갈리는 경우가 많다.

먼저, 이클립스(Eclipse) 또는 비주얼 스튜디오(Visual Studio)와 같이 비주얼을 강조하는 개발툴에서는 GUI 방식의 소스 제어 플러그인을 사용하는 경우가 대부분이다. 이런 환경에서는 키보드와 마우스를 함께 사용하는 경우이고 아이콘(icon)으로 수정된 파일을 바로 확인할 수 있다.

반면, SVN 또는 Git 의 CMD 도구의 사용이 익숙해질 경우 상당히 빠르게 명령을 사용하거나 결과를 확인할 수 있다. 그리고 개인용 컴퓨터의 성능에 거의 영향을 받지 않고 소스 코드를 개발할 수 있고, 손이 마우스와 키보드로 번갈아가며 사용할 필요가 없어 익숙한 사람에게는 더할 나위 없이 편리하다. 더불어, SSH와 같은 단순 Plain Text 환경에서도 제어가 가능하기 때문에 사용에 있어 거의 제한도 없다.

하지만 대체적으로 두 방식 모두 GUI 도구를 제공하거나 GUI 공개 소프트웨어가 많기 때문에 취향에 맞에 사용할 수 있다.

성능

중앙제어 방식은 모든 동작이 서버 측의 허가 없이는 불가능하거나 반드시 서버와 연결이 되어야 한다. 인트라넷이라면 크게 성능의 손실은 없겠지만, 지역이 다른 사람과 오픈 소스 개발을 하거나 클라우드 소스 컨트롤을 사용하는 경우 매우 느리다.

분산제어 방식은 모든 동작이 대부분 로컬에서 이루어 진다. Push, Fetch 같은 동작만이 서버와 연결이 필요하다. 때문에 성능이 매우 좋은 것이 특징이다. 하지만, 중앙제어 방식과 다르게 많은 데이터를 로컬에 저장해야 하므로 중앙제어 방식보다 로컬에 충분한 용량이 확보되어야 한다.

결론

몇 가진 기본적인 관점에서 깊지 않은 내용으로 중앙제어 방식의 소스제어 컨트롤과 분산제어 방식의 소스 컨트롤을 살펴보았다.

필자에게 어떤 것을 사용할지 묻는다면, 작은 개발 조직과 기업 환경에서는 중앙제어 방식을 권장하고 싶다. 많은 소프트웨어 개발 조직에서 여전히 통제하에 소프트웨어 개발을 하기를 원한다. 그리고 암묵적인 소프트웨어 개발 프로세스를 명시적인 프로세스로 개선하고자 하는 곳도 과거보다 많이 생겼다. 이런 환경은 중앙제어 방식이 더 효과적이라 믿는다.

반대로 분산제어 방식은 패키지를 개발하는 기업이나 IT 컨설팅, 국지적 개발 환경이 필요한 경우 효과적일 것이라 생각한다. 물론 기업 환경과 맞지 않는다는 것이 아니며, 통상적인 경우를 말한다.

필자는 우연히 Stack Overflow에서 매우 흥미로운 주제를 발견하였다. 바로 [Git vs Team Foundation Server [closed]]11 인데, 어느 개발팀의 분산제어 방식과 중앙제어 방식의 대결 구도에서 어떤 것을 선택해야 할 것인가에 대한 논의였다. (참고로 필자는 최근 git을 더 좋아한다.)

내용인 즉, 자신의 개발팀에 Git를 도입시켰으나, 개발 팀원들은 팀 파운데이션 서버(Team Foundation Server)로 바꾸길 원했다. 이 질문에 추천 답변의 내용은 ’Git을 버려라. Git을 계속 쓰다가는 계속 비난을 받고 싸우게 될거다’고 한다.

결론은 소스제어 컨트롤(Source Control)은 개인이 아무리 좋고 훌륭한 소스제어라고 생각하더라도 다른 사람들은 그렇게 생각하지 않을 수 있고, 선택에 있어서 다수의 의견에 귀 귀울이는 것이 좋을 것 같다.

I think, the statement

everyone hates it except me

makes any further discussion waste: when you keep using Git, they will blame you if anything goes wrong.
Apart from this, for me Git has two advantages over a centralized VCS that I appreciate most (as partly described by Rob Sobers):
automatic backup of the whole repo: everytime someone pulls from the central repo, he/she gets a full history of the changes. When one repo gets lost: don’t worry, take one of those present on every workstation.
offline repo access: when I’m working at home (or in an airplane or train), I can see the full history of the project, every single checkin, without starting up my VPN connection to work and can work like I were at work: checkin, checkout, branch, anything.
But as I said: I think that you’re fighting a lost battle: when everyone hates Git, don’t use Git. It could help you more to know why they hate Git instead of trying them to convince them.
If they simply don’t want it ’cause it’s new to them and are not willing to learn something new: are you sure that you will do successful development with that staff?

Does really every single person hate Git or are they influenced by some opinion leaders? Find the leaders and ask them what’s the problem. Convince them and you’ll convince the rest of the team.

If you cannot convince the leaders: forget about using Git, take the TFS. Will make your life easier.


Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. 이성훈 2018.05.10 14:53 Address Modify/Delete Reply

    분산제어 서버를 이용하면 프라이빗 블록체인과 차이가 없는건가요..?!