이전과 같이 SQL Server 전체 업그레이드가 잘못 권고 되었습니까?


78

SQL Server 6.5 이후로 SQL Server를 사용하거나 사용하지 않고 작업했지만, 여전히 제 머리에 울리는 오래된 조언은 전체 업그레이드를 수행하지 않아야했습니다.

현재 2008 R2 DEV 및 TEST 시스템을 SQL Server 2012로 업그레이드하고 있으며 동일한 하드웨어를 사용해야합니다. 보고 서비스 구성을 복원 할 필요가 없다는 생각은 매우 매력적이며 시간을 현명하게 사용합니다. 관련된 분석 서비스가 없거나 비정상적이거나 비표준적인 것이 없으며 데이터베이스 엔진 및보고 서비스 만 설치됩니다.

전체 업그레이드와 관련하여 심각한 문제가 발생한 사람이 있습니까? 또는 전체 업그레이드에 대한 내 입장을 재평가해야합니까?


보고 서비스가 설치된 1 대의 서버에서 전체 업그레이드를 수행하기로 선택했습니다. 내가 만난 유일한 문제는 기본 클라이언트 11과 함께 SSMS에서 가져 오기 내보내기 도구를 사용하려고 시도한 것입니다. 인식 할 수없는 데이터 유형에 대한 오류로 변환 시도가 실패했습니다. 내가 사용한 해결 방법은 패키지를 저장하고 SQL 데이터 도구 (BIDS 교체)에서 실행하는 것이 었습니다. SSIS 2008의 구성 파일을 덮어 쓰지 않는 것과 관련이 있다고 생각합니다. 나중에 나에게
일어났다

답변:


92

정말 짧은 답변 -제자리에 괜찮습니다. 나중에 구성을 검토하고 SQL Server 2012에 대한 모범 사례를 구현할 수 있습니다.

SQL Server 업그레이드 / 마이그레이션에 대한 더 긴 답변

따라서 이것은 의견 일이며 반드시 틀렸거나 정답은 아니지만 여러 가지 이유로 내부 스타일 마이그레이션을 선호합니다. 즉, 여러 가지 이유로 내 클라이언트 중 일부는 현재 위치를 수행하는 것 외에는 선택의 여지가 없었으며 실제로 SQL Server 2005 이후에는 전체 업그레이드가 예전만큼 나쁘지 않았습니다.

전체 업그레이드로 마이그레이션을 선호하는 이유

  • 더 쉬운 롤백 -문제가 발생하면 "업그레이드를 중단했습니다.이 문제를 해결하는 동안 연결 문자열을 이전 서버로 변경하십시오"라고 간단히 말하여 롤백 할 수 있습니다. 제자리에 고정되어 있거나 다운되었습니다.
  • 하드웨어 새로 고침 -하드웨어가 빠르게 변경됩니다. 4 년 전에는 귀사에 적합했지만 현재 및 향후 4 년간은 전체 업그레이드로 적합하지 않은 하드웨어에 쉽게 갇힐 수 있습니다. 어쨌든 새 하드웨어를 위해 어떤 시점에서 마이그레이션을 수행해야 할 것입니다.
  • 기분 이 좋아집니다-물론 ... 이것은 주관적이지만, 새로운 OS 설치, 작업 전에 사람의 거미줄이없는 새로운 SQL 설치 (또는 자신이 알고있는 것을 알기 전에)로 시작한다는 것을 알면 기분이 좋습니다. 미래에 두통을 유발할 수 있습니다.
  • 새로운 OS- 마이그레이션을 통해 최신 및 최신 버전이 아닌 경우 새 OS 버전으로 시작할 수 있습니다.
  • 테스트 할 수 있습니다-SQL을 설치하고 데이터베이스 및 사용량으로 클라우드를 클라우드 처리하기 전에 새 머신에 대한 기준을 세우고 싶습니까? 지금 할 수 있습니다.
  • 모범 사례를 살펴 보는 것이 더 쉬운 경우가 있습니다 . SQL Server 서비스 계정이 로컬 관리자 일 수 있습니다. 아마도 Builtin Administrators가 SA 서버 역할을하고있을 것입니다. 어쩌면 상황이 서로 해킹되어 이전에 작동했을 수도 있습니다. 이 모든 것을 고치고 새로 시작할 수 있습니다.
  • 무료 테스트 환경 및 추가 수면 -이 새로운 환경을 실제로 구현할 때 실제 컷 오버 하루 전에 작업 할 수있는 환경을 갖추면 큰 이점이 있습니다. 새로운 환경으로 마이그레이션하는 것은 실제 컷 오버 날짜보다 훨씬 앞서 업무 시간 동안이를 구축하고 여러 가지 방법으로 미리 테스트 할 수 있음을 의미합니다. 며칠 동안 모든 응용 프로그램 및 시스템에서 전체 회귀 테스트를 실행할 수 있으며 실제로 최종 복원 / 연결을 수행하고 모든 응용 프로그램을 컷 오버하고 새로운 환경에 액세스하기 전에 안심할 수 있습니다.
  • 한 번에 모든 작업을 수행 할 필요는 없습니다. 제가 직면 한 가장 일반적인 상황은 단지 몇 개의 인스턴스로 통합하려는 환경입니다. 아마도 버전 당 하나, 아마도 "계층"및 버전 당 하나 일 것입니다. 이러한 많은 프로젝트에는 테스트, 프로젝트 계획 및 공급 업체 인증 적시성에 따라 다양한 응용 프로그램 및 데이터베이스에 대해 서로 다른 타임 라인이 있습니다. 마이그레이션을 수행하면 준비가 완료된 데이터베이스를 준비가 완료된 상태로 이동할 수 있으며 어떤 이유로 든 이동할 수없는 데이터베이스에 대한 요청을 계속 처리 할 수 ​​있습니다.

알았지 나는 당신이 말을하고 있지 않다 마이그레이션으로이 작업을 수행 할 수 있습니다. 인플레 이스 (In-Place)는 제대로 작동하며 예산에 새 하드웨어를 구매할 계획이없고이 업그레이드를 위해이를 수행 할 수없는 경우에는 잘 작동합니다. 업그레이드 프로세스의 지원은 6.5 일보다 훨씬 우수하므로이 작업을 수행하는 데 나쁜 위치에 있지 않습니다.

개발 / 테스트를 수행 할 계획이지만 프로덕션을위한 마이그레이션을 수행하려는 경우 프로덕션 전에 하나 이상의 마이그레이션을 고려할 수 있습니다. 이를 통해 미리 체크리스트를 작성하고 생각하지 않은 잠재적 인 문제를 처리 할 수 ​​있습니다.

마이그레이션을위한 연결 / 분리 및 백업 / 복원

마이그레이션 접근 방식을 사용하기로 결정한 경우 여전히 논란의 여지가있는 또 하나의 결정이 있으며 이는 데이터베이스를 새로운 환경으로 옮기는 방법입니다. 기존 서버에서 데이터베이스를 분리하여 새 서버에 연결하거나 백업 한 후 복원 할 수 있습니다.

백업 / 복원을 선호합니다. 분리 / 연결에 대해 가장 큰 장점은 시간이 절약된다는 것입니다. 나를 위해 몇 가지 이유로 백업 / 복원이 이깁니다.

  • 기존 액세스 가능 유지 -소스 서버에 여전히 액세스 가능한 데이터베이스를 보유 할 수 있습니다. 분리 / 연결은 동일하게 수행해야하지만 몇 단계 만 거치면 분리 / 연결로 인한 사람의 실수로 인해 문제가 발생할 수 있습니다.
  • 백업을 보장합니다 . 분리에서 데이터베이스를 가져 와서 백업 단계를 잊어 버리는 대신 해당 백업을 수행했는지 확인했습니다.
  • 인적 오류 -잘못된 파일을 삭제 한 경우, 무언가를 전송하는 위치를 잊어 버리거나 단계를 엉망으로 만들면 데이터베이스의 데이터 및 로그 파일을 이동하여 많은 위험을 감수 할 수 있습니다. 이제 잘라 내기 대신 복사하여이 문제를 완화 할 수 있습니다 (분리 할 경우 잘라 내기 및 붙여 넣기 습관에서 벗어나야 함). SQL Server는 더 이상 해당 파일을 잠그지 않으며 실수로 파일을 삭제하기가 너무 쉽습니다.
  • 정말없는 것이 느린 백업을 복용하고 복사는 좀 더 시간이지만, 내가 그것을 위해 여분의 위험을 지불 할 오전 그렇게 많이하지 않습니다 -. 실제로 전체 복구 모델 및 로그 백업을 사용하면 아래의 "마이그레이션 접근 방법을보다 빠르게 만드는 방법"에 설명 된대로 컷 오버에 대한 다운 타임을 줄입니다.

백업 / 복원을 수행하기로 결정한 경우 기존 소스 데이터베이스는 여전히 온라인 상태입니다. 백업을 수행 한 후 해당 데이터베이스를 오프라인으로 전환하고 싶습니다. 보안, 작업, 연결된 서버, 인증서, 데이터베이스 메일 설정 및 기타 인스턴스 전체 정보를 스크립팅 한 후 한 걸음 더 나아가서 전체 SQL 인스턴스를 오프라인으로 전환하기도합니다. 이것은 테스트 중에 누군가가 "모두 좋아 보인다"고 말하는 문제를 피합니다. 그들이 하루나 이틀 후에 그들이 구 서버의 구 데이터베이스와 대화하고 있다는 것을 깨닫기 위해서만. 이러한 데이터베이스를 오프라인으로 또는 전체 인스턴스를 오프라인으로 설정하면 이러한 오 탐지 및 혼란을 방지 할 수 있습니다.

마이그레이션 접근 속도를 높이는 방법

전체 복구 모델을 사용하여 가동 중지 시간이 거의없는 바쁜 프로덕션 환경에서 기존 환경에서 새로운 환경으로의 전환에 필요한 다운 타임을 최소화 할 수 있습니다. 기본적으로 최신 전체 백업, 차등 백업 및 이미 수행 된 로그 백업을 복원하여 마이그레이션중인 환경을 준비하십시오. NORECOVERY그러면 최종 컷 오버를 위해 수행해야 할 작업은 아직 복원되지 않은 로그 백업을 복원하는 것입니다. 지정하여 복원하려는 최종 로그 백업 WITH RECOVERY. 이러한 방식으로 큰 데이터베이스의 경우 다운 타임 창보다 전체, 차등 및 대부분의 로그 복원 비용을 지불함으로써 실제 컷 오버 다운 타임 창을 크게 최소화 할 수 있습니다. 의견에서 이것을 지적한 Tao 에게 감사드립니다 !

전체 업그레이드를보다 안전하게 만드는 방법

적절한 접근 방식을 선택할 때 경험과 결과를 개선하기 위해 할 수있는 몇 가지 사항.

  • 백업 -환경의 모든 사용자 및 시스템 데이터베이스를 적절한 백업을 미리 수행하여 양호하게 유지하십시오. (재해 발생시 스스로 감사 할 수 있습니다.) 해당 환경에서 SQL 및 OS 설치에 대한 구성 정보를 스크립팅하십시오.
  • 시작하기 전에 잘 테스트 하십시오-환경이 좋고 데이터베이스가 좋은지 확인하십시오. 오류 로그를보고 DBCC CHECKDB를 정기적으로 실행하는 것과 같은 작업을 수행해야하지만 전체 업그레이드를 수행하기 전에 시작하는 것이 좋습니다. 미리 문제를 해결하십시오.
  • OS 상태 확인-SQL이 정상인지 확인하지 말고 서버가 정상인지 확인하십시오. 시스템 또는 응용 프로그램 오류 이벤트 로그에 심한 오류가 있습니까? 여유 공간은 어떻습니까?
  • 최악의 상황을 대비하라 -얼마 전 블로그 포스트 시리즈 를 통해 실패에 대비 하지 않으면 실제로 실패 준비가되어 있다는 전제를 밟았다 . 따라서 발생할 수있는 문제를 생각하고 이에 따라 미리 처리하십시오. "실패"마인드에 몸을 맡기면 그렇지 않은 일에 대해 생각하게됩니다.

업그레이드 또는 마이그레이션 점검 목록의 중요성

업그레이드를 수행하기로 결정한 경우 (정확한 위치 또는 마이그레이션 여부) 점검 목록 작성 및 각 환경에서이 점검 목록 사용을 진지하게 고려해야합니다. 이 체크리스트에 여러 가지를 포함해야합니다.

  1. 시작시 -테스트 업그레이드 수행과 같은 작업을 수행하고 최신 데이터베이스 호환성 수준에서 응용 프로그램을 테스트하고 SQL Server 업그레이드 관리자 와 같은 도구를 미리 실행하여 SQL 을 수행하기 전에 완료해야 할 작업 종류를 확인하십시오. 서버 업그레이드 또는 마이그레이션
  2. 사전 단계 -정리, OS 작업, 미리 패치, 업그레이드를위한 응용 프로그램 준비 (정리 종료, 연결 문자열 작업), 백업
  3. 업그레이드 / 마이그레이션 단계 -업그레이드 또는 마이그레이션이 성공하고 올바른 순서로 수행해야하는 모든 작업. 데이터베이스에 대한 설치, 변경 (또는 테스트 및 접근 방식에 따라 변경되지 않음) 호환성 모드 변경
  4. 마이그레이션 후 / 업그레이드 단계 -다양한 테스트, 새 버전 또는 새 서버 구성 옵션 게시, 모범 사례 구현, 보안 변경 등
  5. 롤백 단계 -모든 단계에서 롤백 단계와 중요 시점이 있어야합니다. 당신이 이것을 멀리하고 이것이 일어날 경우, 당신은 무엇을 할 것인가? "전체 롤백"기준은 무엇입니까? 그리고 롤백을 수행하는 방법 (역 연결 문자열 변경, 설정 변경, 이전 버전으로 돌아 가기, 현재 위치로 다시 설치, 마이그레이션하는 경우 이전 서버로 돌아 가기 등)

그런 다음 프로덕션 업그레이드를 수행 할 담당자는 프로덕션 이외의 일부 환경에서 체크리스트를 따르도록해야합니다. 특히 닫는 담당자는 가능하면 프로덕션과 비슷합니다 (내가 말했듯이 "Prod of South prod"). 그들이 체크리스트에서 벗어 났거나 체크리스트가 부족하여 즉흥적으로해야했습니다. 그런 다음 변경 사항을 병합 하여 생산 변경과 함께 즐기 십시오.

마이그레이션 또는 업그레이드 후 철저히 마이그레이션을 테스트하는 것의 중요성을 지나치게 강조 할 수는 없습니다. 업그레이드 중에 롤백 결정을 내리는 것은 쉬운 일입니다. 특히 마이그레이션 중에는 쉽습니다. 불편한 것이있는 경우, 마이그레이션 과정에서 효과적이고 안정적으로 문제를 해결할 수없는 경우 롤백하고 파악하십시오. 이 새로운 환경에 살고 사용자가 연결되면 롤백이 어려운 작업이됩니다. SQL Server 데이터베이스를 이전 버전으로 복원 할 수 없습니다. 이는 수동 작업 및 데이터 마이그레이션을 의미합니다. 나는 항상 오래된 환경을 죽이기 위해 몇 주를 기다립니다. 그러나 실제 사용자가 새로운 환경을 만지기 전에 모든 문제를 찾아서 오래된 환경이 필요하지 않도록 최선을 다해야합니다. 업그레이드 / 마이그레이션을 시작하기 전에하는 것이 좋습니다.

SQL Server Reporting Services 마이그레이션 / 업그레이드에 대한 빠른 참고 사항 SSRS 설치 마이그레이션은 많은 사람들이 생각하는 어려운 작업이 아닙니다. 이 technet / books 온라인 기사는 실제로 매우 편리합니다 . 이 기사에서 가장 중요한 경고 중 하나는 특히 예약 된 보고서 전자 메일 수신자 전자 메일 주소, 여러 연결에 대한 연결 정보 등과 같은 중요한 정보가 많이 저장된 경우 "암호화 키 백업" 입니다. 내 고객 중 한 명에게 그것이 얼마나 중요한지 물을 수 있습니다. 그들은 내가 그 단계를 망쳐 놓고 보고서 일정과 연결 문자열 권한을 수정하는 데 많은 시간을 보냈기 때문에 알고 있습니다.


14

내 경험상 이전과 동일한 의사 결정 프로세스가 이루어져야합니다. AFAIK에는 MS SQL Server 제품 자체 내에서 SQL Server를 설치 한 '세계 체인저'와 수백만 줄의 코드가있는 소프트웨어를 출시 할 때 발생할 수있는 잠재적 인 문제가 없었습니다. 나쁜 일이 생길 수 있으며 이제 'ROLLBACK'옵션이 없습니다.

그러나 다른 대안이 있습니다. 시스템 스냅 샷 생성, 다른 곳으로 복원, 업그레이드 수행 및 수행 상황을 고려할 수 있습니다. 이 테스트는 많은 편의를 제공하지만 제품 상자에 아무런 문제가 발생하지 않는다고 절대 보장하지는 않습니다. 그러나 이것은 SQL 6.5 일에 다시 사용할 수 없었던 옵션입니다.

최악의 시나리오를 가정합니다. 전체 업그레이드를 수행하면 비참하게 실패합니다. 그런 다음 RTO 및 RCO 내에서이를 복구해야합니다. 비즈니스는 위험을 이해하고 있으며이를 완화 할 계획이 있습니까?

이것으로 사업이 좋지 않으면 내 조언이되지 않습니다.


2

가상 환경에서 서버를 실행중인 경우 클론에서 스냅 샷을 수행 한 다음 전체 업그레이드를 적용하고 인스턴스를 테스트하여 업그레이드가 성공했는지 확인할 수 있습니다. 작동하면 스냅 샷을 적용하고 복제본을 프로덕션 서버로 만들 수 있습니다. 제대로 작동하지 않으면 스냅 샷을 삭제하고 업그레이드 전 이미지로 돌아가서 다시 시도하거나 복제본과 전체 마이그레이션을 삭제할 수 있습니다.


1
스토리지가 가상화되고 스냅 샷의 일부인 경우에만 해당됩니다. 스토리지가 VM에 직접 연결된 경우 스냅 샷이 복원 될 때 '롤백'되지 않습니다 ...
Remus Rusanu

1

대규모 하드웨어 투자로 인해 현재 SQL Server 버전 (2012, 3 서버, 22 인스턴스, ~ 300 데이터베이스)을 유지하면서 OS 만 업그레이드해야했습니다. 미러링 등과 같은 복잡한 설정이 없습니다.

이 예제는 SQL Server가 업그레이드되지 않기 때문에 질문과 정확히 일치하지 않습니다. 표시된 단계가 실제로 실제 마이그레이션보다 간단하기 때문에 이것이 여전히 좋은 대답이라고 생각합니다.

개요 : 외부 드라이브는 주로 예방책으로 전체 백업을 수행하기 위해 연결되었습니다. 모델과 msdb 만 실제로 외부 드라이브에서 복원됩니다. 분리 / 부착을 위해 ldf / mdf를 그대로 두었다. 일부 로컬 계정은 DB 내에서 참조되었습니다. OS에서 재 작성된 후 SID가 변경 될 수 있으므로 DB 내의 참조가 재 작성되었습니다.

다음은 우리를 위해 일한 단계입니다.

1) 12 단계 (서버 역할) 및 18-23 단계에서 복원 될 서버 레벨 설정에 유의하십시오.

2) SQL Server 2012를 SP3으로 패치합니다 (시스템 데이터베이스를 복원하려면 일관성이 필요함).

3) 각 인스턴스에서 버전이 일치하는지 확인하십시오. "@@ 버전 선택"

4)이 스크립트를 실행하여이 6 개의 스크립트를 생성하십시오. 인스턴스가 많은 경우 Redgate SQL Multiscript는 시간을 크게 절약 할 수 있습니다 (도구-> 옵션 => 줄 길이를 최대 (8192)로 조정 한 다음 텍스트 출력 사용).

  • 지원
  • 복원
  • 떼다
  • 붙이다
  • 로그인 재 작성
  • 사용자를 로그인에 다시 연결

    -- (1) BACKUP / (2) RESTORE
    --    
    --*** SET THESE to external drive location
    --*** and create the Destination Directories
    declare 
        @backupInstanceDir  varchar(300) = 'F:\ExternalDriveBackups\' + replace(@@servername, '\', '_'),
        @dateSuffix         varchar(100) = '2015-12-14'; 
    
    if (object_id('tempdb..DatabaseStatus') is not null)
    drop table #DAtabseSTatus;
    
    select 
        d.name DbName, 
        d.state_desc DbState,
        d.user_access_desc UserMode,
        convert(bit, (d.is_read_only * -1 + 1)) as IsWritable,
        d.is_trustworthy_on as IsTrustWorthy,
        d.is_in_standby IsInStandby,
        d.recovery_model_desc RecoveryModel,
        suser_sname(d.owner_sid) as Owner,
        convert(bit, 
            case when d.database_id <= 4 or d.is_distributor = 1
                then 1
                else 0
            end) as IsSystemDb,
        mf.type_desc as FileType,
        mf.name FileName,
        mf.state FileState,
        mf.state_desc FileStatDesc,
        mf.physical_name PhysicalName,
        mf.type as FileTypeId    
    into #DatabaseStatus
    from
        sys.master_files AS mf
    join sys.databases AS d
    ON  mf.database_id = d.database_id
    where
        1=1
    order by
        d.name,
        mf.physical_name;
    
    if object_id('tempdb..#sqlOut') is not null
        drop table #sqlOutBU
    
    if object_id('tempdb..#sqlOut') is not null
        drop table #sqlOutRE
    
    create table #sqlOutBU
    (
        Command nvarchar(max) not null,
        Row int identity(1,1) not null primary key
    );
    
    create table #sqlOutRE
    (
        Command nvarchar(max) not null,
        Row int identity(1,1) not null primary key
    );
    
    insert into #sqlOutBU select char(10) + '-- BACKUP SCRIPT' + char(10);
    insert into #sqlOutRE select char(10) + '-- RESTORE SCRIPT' + char(10);
    
    
    insert into #sqlOutBU select char(10) + char(10) + '/* ---------------------------------------------------------------------------------------------' + char(10) + 
    'ServerName: ' + @@servername + char(10) + 'ServiceName: ' + @@servicename + char(10) + 'Version: ' + @@version + 
    '--------------------------------------------------------------------------------------------- */';
    
    insert into #sqlOutRE select char(10) + char(10) + '/* ---------------------------------------------------------------------------------------------' + char(10) + 
    'ServerName: ' + @@servername + char(10) + 'ServiceName: ' + @@servicename + char(10) + 'Version: ' + @@version + 
    '--------------------------------------------------------------------------------------------- */';        
    
    PRINT '--Script for Backing up all DBs in a SQL Server Instance to a specific location' 
    
    SET nocount ON 
    
    insert into #sqlOutBU select char(10) + 
    '--' + char(10) + '-- BACKUP ' + @@servername + '--' + char(10) + 
    'use [Master]; set deadlock_priority high;' + char(10);
    
    insert into #sqlOutRE select '
    -- RESTORE
    --
    -- BE SURE TO BACKUP SYSTEM DBS TO AN ALTERNATE LOCATION JUST BEFORE RESTORING!
    --
    use [Master]; set deadlock_priority high;' + char(10);
    
    DECLARE @dbname nvarchar(128) 
    declare dblist_cursor cursor fast_forward for 
    select [name] from master.sys.databases where [name] != 'tempdb'
    order by iif(database_id <= 4, '0', '1') + [name]
    
    open dblist_cursor 
    fetch next from dblist_cursor into @dbname 
    
    while @@fetch_status = 0 
    begin 
    
        declare @bak nvarchar(300) = @backupInstanceDir + '\' + @dbname + '_' + @dateSuffix + '.bak';
    
        insert into #sqlOutBU select char(10) + 'backup database [' + @dbname + '] to disk = ''' + @bak + ''' WITH COPY_ONLY, NOFORMAT, NOINIT, ' + char(10) + 
            'NAME = N''' + @dbName + '-Full'', SKIP, NOREWIND, NOUNLOAD, COMPRESSION, STATS = 25;';
    
        insert into #sqlOutRE select 'restore database [' + @dbName + '] from disk = ''' + @bak + ''' WITH FILE = 1,' + char(10) +
        (
            select '    move ''' + FileName + ''' to ''' + PhysicalName + '''' From #DatabaseStatus
            where FileType = 'Rows' and DbName = @dbName
        ) + ',' + char(10) +
        (
            select '    move ''' + FileName + ''' to ''' + PhysicalName + '''' From #DatabaseStatus
            where FileType = 'Log' and DbName = @dbName
        ) + ',' + char(10) +
        '    NOUNLOAD, REPLACE, STATS = 25;' + char(10);               
    
        fetch next from dblist_cursor into @dbname 
    end 
    
    close dblist_cursor 
    deallocate dblist_cursor 
    
    insert into #sqlOutBU select char(10) + 'go' + char(10);
    insert into #sqlOutRE select char(10) + 'go' + char(10);
    
    select Command from #sqlOutBU order by Row; -- BACKUP SCRIPT
    select Command from #sqlOutRE order by Row; -- RESTORE SCRIPT
    
    go
    
    
    
    --
    -- (3) DETACH  -  Org Author: Artemakis Artemiou
    --      
    
    if object_id('tempdb..#sqlOutDT') is not null
        drop table #sqlOutDT
    
    create table #sqlOutDT
    (
        Command nvarchar(max) not null,
        Row int identity(1,1) not null primary key
    );
    
    insert into #sqlOutDT select char(10) + '-- DETACH all DBs from a SQL Server Instance' + char(10);      
    
    insert into #sqlOutDT select char(10) + char(10) + '/* ---------------------------------------------------------------------------------------------' + char(10) + 
    'ServerName: ' + @@servername + char(10) + 'ServiceName: ' + @@servicename + char(10) + 'Version: ' + @@version + 
    '--------------------------------------------------------------------------------------------- */';
    
    SET nocount ON 
    
    insert into #sqlOutDT select char(10) + '--' + char(10) + '-- DETACH ' + @@servername + char(10) + '--' + char(10) + '
    use MAster; set deadlock_priority high;' + char(10) + char(10);
    
    DECLARE @dbname nvarchar(128) 
    DECLARE dblist_cursor CURSOR fast_forward FOR 
    SELECT [name] 
    FROM   master.sys.databases 
    WHERE  database_id > 4 
    
    OPEN dblist_cursor 
    FETCH next FROM dblist_cursor INTO @dbname 
    
    WHILE @@FETCH_STATUS = 0 
    BEGIN 
        insert into #sqlOutDT select
        'alter database ' + @dbname + ' set single_user with rollback immediate;' + char(10) +
        'EXEC sp_detach_db ''' + @dbname + ''', ''true'';' + char(10);
        FETCH next FROM dblist_cursor INTO @dbname 
    END 
    
    CLOSE dblist_cursor 
    DEALLOCATE dblist_cursor 
    
    insert into #sqlOutDT select char(10) + 'go' + char(10);
    select Command from #sqlOutDT order by Row;
    
    go
    
    
    
    --
    -- (4) ATTACH  -  Org Author: Artemakis Artemiou
    --    
    
    if object_id('tempdb..#sqlOut') is not null
        drop table #sqlOutAT
    
    create table #sqlOutAT
    (
        Command nvarchar(max) not null,
        Row int identity(1,1) not null primary key
    );
    
    insert into #sqlOutAT select char(10) + '-- ATTACH ALL DBs to a SQL Server Instance' + char(10);
    
    insert into #sqlOutAT select char(10) + char(10) + '/* ---------------------------------------------------------------------------------------------' + char(10) + 
    'ServerName: ' + @@servername + char(10) + 'ServiceName: ' + @@servicename + char(10) + 'Version: ' + @@version + 
    '--------------------------------------------------------------------------------------------- */';
    
    SET NOCOUNT ON
    
    insert into #sqlOutAT select char(10) + '--' + char(10) + '-- ATTACH ' + @@servername + char(10) + '--' + char(10) + 
    'use MAster;' + char(10) + char(10);
    
    DECLARE @dbname nvarchar(128);
    
    DECLARE DBList_cursor CURSOR fast_forward FOR 
    select [name] from master.sys.databases where database_id > 4
    order by name;
    
    OPEN DBList_cursor
    
    FETCH NEXT FROM DBList_cursor 
    INTO @dbname
    
    WHILE @@FETCH_STATUS = 0
    BEGIN
    
    declare @attach_TSQL_script varchar(max)
    set @attach_TSQL_script=''
    set @attach_TSQL_script=@attach_TSQL_script+'CREATE DATABASE ' + @dbname +' ON ' 
    
    declare @tsql varchar(max),@filename varchar(max)
    set @tsql='DECLARE DBFiles_cursor CURSOR FOR select [filename] from '+ @dbname + '.sys.sysfiles'
    
    execute (@tsql) 
    
    PRINT '--'+@dbname 
    
    OPEN DBFiles_cursor
    FETCH NEXT FROM DBFiles_cursor INTO @filename
    
    WHILE @@FETCH_STATUS = 0
    BEGIN   
    set @attach_TSQL_script=@attach_TSQL_script+ char(10)+'    (FILENAME = '''+ @filename +'''),' 
    FETCH NEXT FROM DBFiles_cursor INTO @filename
    END
    
    set @attach_TSQL_script=SUBSTRING(@attach_TSQL_script,0,len(@attach_TSQL_script))
    set @attach_TSQL_script=@attach_TSQL_script+ char(10) +'    FOR ATTACH;';
    
    insert into #sqlOutAT select @attach_TSQL_script + char(10);
    
    PRINT @attach_TSQL_script 
    PRINT ''
    
    CLOSE DBFiles_cursor
    DEALLOCATE DBFiles_cursor
    
    FETCH NEXT FROM DBList_cursor 
    INTO @dbname
    
    END 
    
    CLOSE DBList_cursor
    DEALLOCATE DBList_cursor
    
    insert into #sqlOutAT select char(10) + 'go' + char(10);
    select Command from #sqlOutAT order by Row;
    go
    
    
    
    --
    -- (5) GENERATE A 'RE-CREATE LOGINS' SCRIPT
    --
    -- This script was modified from a version that was designed to copy from one server to another:
    --      http://stackoverflow.com/a/5983773/538763
    --
    
    
    USE [master]
    
    if object_id('tempdb..#sqlOut') is not null
    drop table #sqlOut;
    
    create table #sqlOut
    (
    Command nvarchar(max) not null,
    Row int identity(1,1) not null primary key
    );
    
    insert into #sqlOut select char(10) + '-- RECREATE LOGINS' + char(10);
    
    
    insert into #sqlOut select char(10) + char(10) + '/* ---------------------------------------------------------------------------------------------' + char(10) + 
    'ServerName: ' + @@servername + char(10) + 'ServiceName: ' + @@servicename + char(10) + 'Version: ' + @@version + 
    '--------------------------------------------------------------------------------------------- */';
    
    insert into #sqlOut select 'use Master;' + char(10);
    go
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    declare @Debug bit = 0;
    declare @PartnerServer varchar(100) = @@SERVICENAME;  -- use current server before it is shutdown (disabled below)
    
    declare
        @MaxID int,
        @CurrID int,
        @SQL nvarchar(max),
        @LoginName sysname,
        @IsDisabled int,
        @Type char(1),
        @SID varbinary(85),
        @SIDString nvarchar(100),
        @PasswordHash varbinary(256),
        @PasswordHashString nvarchar(300),
        @RoleName sysname,
        @Machine sysname,
        @PermState nvarchar(60),
        @PermName sysname,
        @Class tinyint,
        @MajorID int,
        @ErrNumber int,
        @ErrSeverity int,
        @ErrState int,
        @ErrProcedure sysname,
        @ErrLine int,
        @ErrMsg nvarchar(2048);
    
    declare @Logins Table (LoginID int identity(1, 1) not null primary key,
                        [Name] sysname not null,
                        [SID] varbinary(85) not null,
                        IsDisabled int not null,
                        [Type] char(1) not null,
                        PasswordHash varbinary(256) null)
    declare @Roles Table (RoleID int identity(1, 1) not null primary key,
                    RoleName sysname not null,
                    LoginName sysname not null)
    declare @Perms Table (PermID int identity(1, 1) not null primary key,
                    LoginName sysname not null,
                    PermState nvarchar(60) not null,
                    PermName sysname not null,
                    Class tinyint not null,
                    ClassDesc nvarchar(60) not null,
                    MajorID int not null,
                    SubLoginName sysname null,
                    SubEndPointName sysname null)
    
    Set NoCount On;
    
    If CharIndex('\', @PartnerServer) > 0
    Begin
    Set @Machine = LEFT(@PartnerServer, CharIndex('\', @PartnerServer) - 1);
    End
    Else
    Begin
    Set @Machine = @PartnerServer;
    End
    
    -- Get all Windows logins from principal server
    Set @SQL = 'Select P.name, P.sid, P.is_disabled, P.type, L.password_hash' + CHAR(10) +
        'From ' /*+ QUOTENAME(@PartnerServer) + '.*/ + 'master.sys.server_principals P' + CHAR(10) +
        'Left Join '/* + QUOTENAME(@PartnerServer) + '.*/ + 'master.sys.sql_logins L On L.principal_id = P.principal_id' + CHAR(10) +
        'Where P.type In (''U'', ''G'', ''S'')' + CHAR(10) +
        'And P.name <> ''sa''' + CHAR(10) +
        'And P.name Not Like ''##%''' + CHAR(10) +
        'and P.Name Not like ''NT SERVICE%''' + CHAR(10) +
        'And CharIndex(''' + @Machine + '\'', P.name) = 0;';
    
    Insert Into @Logins (Name, SID, IsDisabled, Type, PasswordHash)
    Exec sp_executesql @SQL;
    
    -- Get all roles from principal server
    Set @SQL = 'Select RoleP.name, LoginP.name' + CHAR(10) +
        'From '/* + QUOTENAME(@PartnerServer) + '.*/ + 'master.sys.server_role_members RM' + CHAR(10) +
        'Inner Join '/* + QUOTENAME(@PartnerServer) + .*/ +'master.sys.server_principals RoleP' +
        CHAR(10) + char(9) + 'On RoleP.principal_id = RM.role_principal_id' + CHAR(10) +
        'Inner Join '/* + QUOTENAME(@PartnerServer) + '.*/ + 'master.sys.server_principals LoginP' +
        CHAR(10) + char(9) + 'On LoginP.principal_id = RM.member_principal_id' + CHAR(10) +
        'Where LoginP.type In (''U'', ''G'', ''S'')' + CHAR(10) +
        'And LoginP.name <> ''sa''' + CHAR(10) +
        'And LoginP.name Not Like ''##%''' + CHAR(10) +
        'And LoginP.name Not Like ''NT SERVICE%''' + CHAR(10) +
        'And RoleP.type = ''R''' + CHAR(10) +
        'And CharIndex(''' + @Machine + '\'', LoginP.name) = 0;';
    
    Insert Into @Roles (RoleName, LoginName)
    Exec sp_executesql @SQL;
    
    -- Get all explicitly granted permissions
    Set @SQL = 'Select P.name Collate database_default,' + CHAR(10) +
        '   SP.state_desc, SP.permission_name, SP.class, SP.class_desc, SP.major_id,' + CHAR(10) +
        '   SubP.name Collate database_default,' + CHAR(10) +
        '   SubEP.name Collate database_default' + CHAR(10) +
        'From '/* + QUOTENAME(@PartnerServer) + '.*/ + ' master.sys.server_principals P' + CHAR(10) +
        'Inner Join '/* + QUOTENAME(@PartnerServer) + '.*/ + ' master.sys.server_permissions SP' + CHAR(10) +
        CHAR(9) + 'On SP.grantee_principal_id = P.principal_id' + CHAR(10) +
        'Left Join '/* + QUOTENAME(@PartnerServer) + '.*/ + ' master.sys.server_principals SubP' + CHAR(10) +
        CHAR(9) + 'On SubP.principal_id = SP.major_id And SP.class = 101' + CHAR(10) +
        'Left Join '/* + QUOTENAME(@PartnerServer) + '.*/ + ' master.sys.endpoints SubEP' + CHAR(10) +
        CHAR(9) + 'On SubEP.endpoint_id = SP.major_id And SP.class = 105' + CHAR(10) +
        'Where P.type In (''U'', ''G'', ''S'')' + CHAR(10) +
        'And P.name <> ''sa''' + CHAR(10) +
        'And P.name Not Like ''##%''' + CHAR(10) +
        'And P.name Not Like ''NT SERVICE%''' + CHAR(10) +
        'And CharIndex(''' + @Machine + '\'', P.name) = 0;'
    
    Insert Into @Perms (LoginName, PermState, PermName, Class, ClassDesc, MajorID, SubLoginName, SubEndPointName)
    Exec sp_executesql @SQL;
    
    --select * from @Logins;
    --select * from @Roles;
    --select * from @perms;
    
    
    Select @MaxID = Max(LoginID), @CurrID = 1
    From @Logins;
    
    While @CurrID <= @MaxID
    Begin
    Select @LoginName = Name,
        @IsDisabled = IsDisabled,
        @Type = [Type],
        @SID = [SID],
        @PasswordHash = PasswordHash
    From @Logins
    Where LoginID = @CurrID;
    
    --    If Not Exists (Select 1 From sys.server_principals
    --              Where name = @LoginName)
    Begin
    
        set @sql = char(10);
        set @sql += 'If Not Exists (Select 1 From sys.server_principals Where name = ''' + @LoginName + ''')' + char(10);
        set @sql += 'begin' + char(10) + '    ';
    
        Set @SQL += 'Create Login ' + quotename(@LoginName)
        If @Type In ('U', 'G')
        Begin
            Set @SQL = @SQL + ' From Windows;'
        End
        Else
        Begin
            Set @PasswordHashString = '0x' +
                Cast('' As XML).value('xs:hexBinary(sql:variable("@PasswordHash"))', 'nvarchar(300)');
    
            Set @SQL = @SQL + ' With Password = ' + @PasswordHashString + ' HASHED;  --, ';
    
            Set @SIDString = '0x' +
                Cast('' As XML).value('xs:hexBinary(sql:variable("@SID"))', 'nvarchar(100)');
            Set @SQL = @SQL + 'SID = ' + @SIDString + ';' + char(10);
        End
    
        set @sql += char(10) +
            '    print ''Created Login ' + @loginName  + ''';' + char(10) +
            'end' + char(10) +
            'else' + char(10) +
            convert(nvarchar(max), '    print ''Login ' + @loginName + ' already existed. '';') + char(10);
    
        If @Debug = 0
        insert into #sqlOut select @SQL;                      
        Else
        Print @SQL;
    
        If @IsDisabled = 1
        Begin
            Set @SQL = 'Alter Login ' + quotename(@LoginName) + ' Disable;'
            If @Debug = 0
                insert into #sqlOut select @SQL;                              
            Else              
                Print @SQL;              
        End
        End
    Set @CurrID = @CurrID + 1;
    End
    
    
    insert into #sqlOut select char(10) + 'use Master;' + char(10);
    
    Select @MaxID = Max(RoleID), @CurrID = 1
    From @Roles;
    
    While @CurrID <= @MaxID
    Begin
    Select @LoginName = LoginName,
        @RoleName = RoleName
    From @Roles
    Where RoleID = @CurrID;
    
    /*  If Not Exists (Select 1 From sys.server_role_members RM
                Inner Join sys.server_principals RoleP
                    On RoleP.principal_id = RM.role_principal_id
                Inner Join sys.server_principals LoginP
                    On LoginP.principal_id = RM.member_principal_id
                Where LoginP.type In ('U', 'G', 'S')
                And RoleP.type = 'R'
                And RoleP.name = @RoleName
                And LoginP.name = @LoginName)*/
    Begin
        If @Debug = 0
        Begin          
            insert into #sqlOut select 'Exec sp_addsrvrolemember @rolename = ''' + @RoleName + ''', @loginame = ''' + @LoginName + ''';';
        End
        Else
        Begin
            Print 'Exec sp_addsrvrolemember @rolename = ''' + @RoleName + ''',';
            Print '     @loginame = ''' + @LoginName + ''';';
        End
    End
    
    Set @CurrID = @CurrID + 1;
    End
    
    
    insert into #sqlOut select char(10) + 'use Master;' + char(10);
    
    
    Select @MaxID = Max(PermID), @CurrID = 1
    From @Perms;
    
    While @CurrID <= @MaxID
    Begin
    Select @PermState = PermState,
        @PermName = PermName,
        @Class = Class,
        @LoginName = LoginName,
        @MajorID = MajorID,
        @SQL = PermState + space(1) + PermName + SPACE(1) +
            Case Class When 101 Then 'On Login::' + QUOTENAME(SubLoginName)
                    When 105 Then 'On ' + ClassDesc + '::' + QUOTENAME(SubEndPointName)
                    Else '' End +
            ' To ' + QUOTENAME(LoginName) + ';'
    From @Perms
    Where PermID = @CurrID;
    
    /*If Not Exists (Select 1 From sys.server_principals P
                Inner Join sys.server_permissions SP On SP.grantee_principal_id = P.principal_id
                Where SP.state_desc = @PermState
                And SP.permission_name = @PermName
                And SP.class = @Class
                And P.name = @LoginName
                And SP.major_id = @MajorID)*/
    Begin
        If @Debug = 0
                insert into #sqlOut select @sql;                      
        Else          
            Print @SQL;          
    End
    
    Set @CurrID = @CurrID + 1;
    End
    
    
    select Command from #sqlOut as SqlOut order by Row;
    go
    
    
    --
    -- (6) Generate a script to Re-link all users to logins based on current state (before shutdown)
    --
    
    use Master;
    
    if object_id('tempdb..#sqlOut') is not null
    drop table #sqlOut;
    
    create table #sqlOut
    (
        Command nvarchar(max) not null,
        Row int identity(1,1) not null primary key
    );
    
    insert into #sqlOut select char(10) + '-- RELINK USERS TO LOGINS' + char(10);
    
    insert into #sqlOut select char(10) + char(10) + '/* ---------------------------------------------------------------------------------------------' + char(10) + 
    'ServerName: ' + @@servername + char(10) + 'ServiceName: ' + @@servicename + char(10) + 'Version: ' + @@version + 
    '--------------------------------------------------------------------------------------------- */';
    
    declare @dbCmd varchar(8000) = '
    use ?;
    
    insert into #sqlOut select char(10) + ''use ?;'' + char(10);  
    
    with links as
    (
    select u.name as UserName,
        l.loginname as LoginName
        from sysusers u 
        join master..syslogins l
        on u.sid = l.sid        
    where u.name != ''dbo''
        and u.isSqlUser = 1 or l.isNtName = 1 or l.isNtGroup = 1
    )
    insert into #sqlOut 
    select ''alter user ['' + UserName + ''] with name = ['' + UserName + ''], login = ['' + LoginName + '']''
    from links
    ';    
    
    exec sp_MSforeachdb @dbCmd;
    
    select Command from #sqlOut order by Row;
    
    go

5) 스크립트를 실행하여 시스템 (마스터, msdb, 모델)을 포함한 모든 DB를 외부 드라이브에 백업합니다.

6) 스크립트를 실행하여 모든 DB 분리

7) C 드라이브가 다시 포맷됩니다. LDF / MDF가 C가 아닌 경우 보존하십시오.

8) Windows Server 2012가 C에 설치되어 있음

9) 원본 시스템 파일에 대한 LDF / MDF가 C 드라이브에없는 경우 이동하십시오.

10) SQL Server 2012가 다시 설치되고 SP3에 패치됩니다. 시스템 사용자 / 그룹 계정 재 작성

11) 시스템 DB를 새로운 위치 또는 파일 이름으로 백업하십시오 (원본을 덮어 쓰지 않도록주의하십시오!).

12) 역할 다시 작성 스 니펫을 실행하십시오. 다음과 같은 것 :

USE [master]
CREATE SERVER ROLE [SomeServerRole]
--ALTER SERVER ROLE [dbcreator] ADD MEMBER [SomeServerRole]
--ALTER SERVER ROLE [bulkadmin] ADD MEMBER [SomeServerRole]
-- ALTER SERVER ROLE [SomeServerRole] ADD MEMBER [SomeMemberOrRole]

13) 로그인 스크립트 재 작성 실행 (로그인이 복원 된 경우 아무 것도하지 않음)

14) SQL AGENT를 중지하십시오.

(여기서 스승님을 회복시킬 수있었습니다)

15) 위의 스크립트를 사용하여 mdf / ldf를 첨부하십시오. 에이. 위의 스크립트를 사용하여 bak에서 수동으로 복원하지 못한 경우.

16) 모델 복원 시도

17) SQL 에이전트가 중지되었는지 확인하십시오. MSDB (링크) 복원 a. 실패하면 작업 + 유지 보수 계획 + 메일 구성 + 운영자를 다시 작성해야합니다.

18) 사용자 로그인 스크립트 열기 ...

    a. If there are master users (rare?) then First Re-Create users for master since it was not restored:
        use master;       
        CREATE USER [ABC] FOR LOGIN [machine\ABC]

    b. Run the rest of the script

19) 서비스 브로커가 원래 값 SELECT 이름, is_broker_enabled FROM sys.databases와 일치하도록 설정하십시오.

    alter database MSDB set single_user with rollback immediate;
    ALTER DATABASE [MSDB] SET ENABLE_BROKER;
    alter database MSDB set multi_user;

20) SQL 에이전트 시작

21) 병렬 임계 값을 원래 값으로 설정

22) 데이터베이스 설정을 원래 값으로 조정하십시오.

 declare @dbCmd varchar(8000) = '
      use ?;
      if db_name() not in (''master'', ''model'', ''tempdb'', ''msdb'')
      begin
             print ''Adjusting [?]...'';    
            alter database [?] set single_user with rollback immediate;
             aLTER AUTHORIZATION ON DATABASE::[?] to [sa];
            -- alter database [?] set trustworthy on;
            ALTER DATABASE [?] SET AUTO_CLOSE OFF WITH NO_WAIT;     
            alter database [?] set multi_user;
      end     
      else
             print ''Skipping [?]...'';
    ';    

    exec sp_MSforeachdb @dbCmd;

23) 직무 소유권 확인 :

select s.name as JobName, l.name as login, SUSER_SNAME(s.owner_sid) AS login2
from  msdb..sysjobs s 
left join master.sys.syslogins l on s.owner_sid = l.sid

SQL Server 버전도 업그레이드 된 경우 모델 및 msdb 데이터베이스가 복원되어 https://support.microsoft.com/en-us/kb/264474 로 인해 작업이 손실되었을 수 있다고 생각하지 않습니다.

빠진 것 :

  • 마스터 데이터베이스의 Orignal 사용자 (드문 경우)
  • 서버 역할
  • ?

0

두 가지 접근 방식 자체에는 아무런 문제가 없습니다. 두 가지를 모두 수행했으며 두 결과 모두 일반적으로 좋습니다.

마이그레이션 방식에 문제가있는 경우 기술적 인 것이 아니라 게으름입니다. 회사가 아직 xxxx 버전으로 완전히 가지 않은 이유는 스윙 마이그레이션을 선택하고 완전히 움직이기 위해 열심히 일하지 않았기 때문입니다. 이제 하나가 아닌 둘 이상의 서버 세트가 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.