SELECT DISTINCT a.name
    FROM sysobjects AS a
                   LEFT JOIN syscomments AS ON a.id = b.id
 WHERE a.xtype = 'P'
       AND b.text LIKE '%찾은문자열%'


dateadd, datediff DATABASE/MS SQL 2016. 1. 12. 16:47

dateadd

-- 월의 마지막 날
select dateadd(month,1,getdate())-day(getdate())
-- 월의 첫째날
select dateadd(day,-(day(getdate()-1)), getdate())
-- 월의 13개월전 첫째날
select dateadd(month,-12,getdate())-(day(getdate())-1)

-- 1일 더하기
select dateadd(day,1,getdate())
-- 1월 더하기
select dateadd(month,1,getdate())
-- 1년 더하기
select dateadd(year,1,getdate())



datediff

datediff( 시간단위구분자, 시작시간, 종료시간 )


 

getdate()+1 은 현재시간에서 1일을 더하는 함수이다.

현재 시간이 2012-12-20 11:50:11 이면, getdate()+1 은 2012-12-21 11:50:11 이 된다

 

 

각각 분단위, 초단위, 시간단위, 일단위, 월단위, 년단위로 구한다.

select DATEDIFF ( mi , getdate() , getdate()+1 ) ==> 1440 분 (1일)

select DATEDIFF ( s , getdate() , getdate()+1 ) ==> 86400 초 (1일)

select DATEDIFF ( hour , getdate() , getdate()+1 ) ==> 24 시간 (1일)

select DATEDIFF ( day , getdate() , getdate()+1 ) ==> 1 일 (1일)

select DATEDIFF ( month , getdate() , getdate()+31 ) ==> 1 개월 (31일)

select DATEDIFF ( year , getdate() , getdate()+730 ) ==> 2 년 (730일)

 

출처: http://lefigaro.tistory.com/14 

출처 : 토토 블로그 http://intomysql.blogspot.kr/2011/01/union-union-all.html


UNION과 UNION ALL 의 차이 및 주의 사항

ANSI SQL에서 제안하는 집합 연산 "UNION", "INTERSECT", "MINUS" 중에서
MySQL에서는 UNION 집합 연산만 제공하고 있다. 
(하지만 MySQL에서 INTERSECT나 MINUS를 다른 형태의 쿼리로 풀어서 사용할 수 있다.)


이 글에서는 UNION 에 대해서 좀 더 자세히 알아 보고자 한다.
UNION 집합 연산은 다시 아래와 같이 두가지 종류로 나누어진다.
  - UNION ALL
  - UNION DISTINCT


우리가 일반적으로 사용하는 방식인 아무런 추가 키워드 없이 UNION 만 사용하는 것은
UNION DISTINCT 를 줄여서 사용하고 있는 것이다
.

UNION ALL과 UNION DISTINCT를 레코드가 많은 결과에 대해서 적용해본 사람은 
아마도 둘의 처리 방식에 대해서 의구심을 가져본 적이 있을 것이다.

레코드 건수가 많아지면 많아질수록 그 성능 차이는 엄청난 차이를 보여줄 것이다.

우선, 아래와 같이 2개씩 동일한 레코드 데이터를 가지고 있는 tab1과 tab2라는 테이블이 있다.

mysql>SELECT fdpk, fddata FROM tab1;
+------+--------+
| fdpk | fddata |
+------+--------+
|    1 | data1  |
|    2 | data2  |
+------+--------+
2 rows in set (0.00 sec)


mysql>SELECT fdpk, fddata FROM tab2;
+------+--------+
| fdpk | fddata |
+------+--------+
|    1 | data1  |
|    2 | data2  |
+------+--------+
2 rows in set (0.01 sec)


그러면, 이 두개 테이블에 대해서 각각 UNION과 UNION ALL을 사용하는 쿼리를 실행해보자.

mysql>SELECT fdpk, fddata
    -> FROM (
    ->   SELECT fdpk, fddata FROM tab1
    ->   UNION ALL
    ->   SELECT fdpk, fddata FROM tab2
    -> ) x;
+------+--------+
| fdpk | fddata |
+------+--------+
|    1 | data1  |
|    2 | data2  |
|    1 | data1  |
|    2 | data2  |
+------+--------+
4 rows in set (0.00 sec)


mysql>SELECT fdpk, fddata
    -> FROM (
    ->   SELECT fdpk, fddata FROM tab1
    ->   UNION
    ->   SELECT fdpk, fddata FROM tab2
    -> ) x;
+------+--------+
| fdpk | fddata |
+------+--------+
|    1 | data1  |
|    2 | data2  |
+------+--------+
2 rows in set (0.00 sec)


두개의 퀴리 실행 결과 UNION은 레코드가 반으로 줄었다.
이미 다들 알고 있다시피 UNION은 UNION DISTINCT와 동일한 작업을 하기 때문에 중복되는 레코드를 제거했음을 알 수 있다.
하지만, UNION ALL의 경우에는 별도의 중복 제거 과정을 거치지 않고 그냥 결과를 내려준다.
아주 중요한 내용이지만, 사실 이 내용을 다들 별로 신경쓰지 않고 모두들 UNION을 즐겨 사용한다.


안타깝게도, MySQL의 실행계획에서는 둘의 차이를 전혀 느낄 수 없다.
+----+--------------+------------+------+..+------+..+------+------+-------+
| id | select_type  | table      | type |..| key  |..| ref  | rows | Extra |
+----+--------------+------------+------+..+------+..+------+------+-------+
|  1 | PRIMARY      | <derived2> | ALL  |..| NULL |..| NULL |    4 |       |
|  2 | DERIVED      | tab1       | ALL  |..| NULL |..| NULL |    2 |       |
|  3 | UNION        | tab2       | ALL  |..| NULL |..| NULL |    2 |       |
|NULL| UNION RESULT | <union2,3> | ALL  |..| NULL |..| NULL | NULL |       |
+----+--------------+------------+------+..+------+..+------+------+-------+


하지만 중복 제거는 그냥 얻을 수 있는 결과가 아니다.그러면, MySQL이 내부적으로 어떻게 중복을 제거하는 것일까 ?

내부적인 처리를 알아보기 전에, 레코드의 중복이라는 표현을 했는데 이 중복의 기준이 무었일까 ?
    1. 각 테이블의 Primary key ?
    2. 전체 테이블의 모든 필드 ?
    3. 각 서브 쿼리에서 SELECT된 튜플(레코드)의 모든 필드 ?


그렇다. 이미 SELECT된 결과를 가지고 UNION하기 때문에 SELECT되기 전의 테이블이나 레코드에 대한 정보는 알 수 없다.
그래서, 중복 여부의 판단은 SELECT된 튜플들에 속해있는 모든 컬럼의 값들 자체가 중복 체크의 기준이 되는 것이다.


자~, 그러면 이제 MySQL이 내부적으로 UNION ALL과 UNION을 처리하는 과정을 알아보자.
1. 최종 UNION [ALL | DISTINCT] 결과에 적합한 임시 테이블(Temporary table)을 메모리 테이블로 생성
2. UNION 또는 UNION DISTINCT 의 경우, Temporary 테이블의 모든 컬럼으로 Unique Hash 인덱스 생성3. 서브쿼리1 실행 후 결과를 Temporary 테이블에 복사
4. 서브쿼리2 실행 후 결과를 Temporary 테이블에 복사
5. 만약 3,4번 과정에서 Temporary 테이블이 특정 사이즈 이상으로 커지면 

    Temporary 테이블을 Disk Temporary 테이블로 변경 
    (이때 Unique Hash 인덱스는 Unique B-Tree 인덱스로 변경됨)
6. Temporary 테이블을 읽어서 Client에 결과 전송
7. Temporary 테이블 삭제


UNION 두 가지의 차이는 2번 과정 딱 하나이다. 중복 제거를 위해서 Temporary 테이블에 인덱스를 생성하느냐 ?. 그렇지 않느냐 ?.별로 중요하지 않은 것 같지만, 이 인덱스로 인해서 3,4번 과정의 작업이 작지 않은 성능 차이가 만들어 내게 된다.
실제 UNION을 실행하는 데이터의 건수에 따라서 다르겠지만, 1.5 ~ 4배 가량의 성능 차이로 UNION ALL이 빠르게 처리된다.
만약 처리중 데이터의 량이 작아서 5번 과정을 거치지 않는다면 메모리 Temporary 테이블에 Hash 인덱스를 사용하기 때문에 

속도 차이가 아주 미세할 것이다. 
하지만 데이터량이 커져서 5번 과정을 거치게 되면 Disk Temporary 테이블에 B-Tree 인덱스를 사용하기 때문에 큰 성능 차이를 보이게 될 것이다.
이 성능 차이는 UNION 하는 두 집합에 중복되는 레코드가 있든 없든 관계 없이 발생할 것이다.


위에서 잠깐 알아보았던, "중복의 기준"을 생각하면, UNION 하는 컬럼들의 수가 많아지고 레코드의 사이즈가 커질수록 두 작업 모두에게 불리하겠지만, UNION ALL보다는 UNION에 더 악영향이 클 것이다.

결론은,
0. UNION 이든지 UNION ALL이든지 사실 그리 좋은 SQL 작성은 아니다. 

    UNION이 필요하다는 것은 사실 두 엔터티(테이블)가 하나의 엔터티(테이블)로 통합이 되었어야 
    할 엔터티들이었는데, 알 수 없는 이유로 분리 운영되는 경우가 상당히 많다. 
    즉 모델링 차원에서 엔터티를 적절히 통합하여 UNION의 요건을 모두 제거하자.
1. 두 집합에 절대 중복된 튜플(레코드)가 발생할 수 없다는 보장이 있다면 UNION ALL을 꼭 사용하자.

    두 집합에서 모두 각각의 PK를 조회하는데, 그 두 집합의 PK가 절대 중복되지 않는 형태
2. 중복이 있다 하더라도 그리 문제되지 않는다면 UNION 보다는 UNION ALL을 사용하자.
3. 만약 UNION이나 UNION ALL을 사용해야 한다면, 최소 필요 컬럼만 SELECT 하자.


'DATABASE' 카테고리의 다른 글

[펌] 트랜잭션 로그 백업(Transaction Log Backup)에 관하여  (0) 2013.11.05
TRUNCATE  (0) 2013.09.25
CRUD 의 중요도?  (0) 2013.08.02
DECODE, RANK()OVER(), UNION/UNION ALL  (1) 2013.08.02
DATA BASE _ 기초  (0) 2013.07.10

f--Getdate()
Select Getdate()

--YYYY/MM/DD
Select Convert(varchar(10),Getdate(),111)

--YYYYMMDD
Select Convert(varchar(10),Getdate(),112)

--HH:MM:SS
Select Convert(varchar(8),Getdate(),108)

--HH:MM:SS:mmm
Select Convert(varchar(12),Getdate(),114)

--HHMMSS
Select Replace(Convert(varchar(8),Getdate(),108),':','')

--HHMMSSmmm
Select Replace(Convert(varchar(12),Getdate(),114),':','')

--YYYY/MM/DD HH:MM:SS
Select Replace(Convert(varchar(30),Getdate(),120),'-','/')

--YYYY/MM/DD HH:MM:SS
Select Replace(Convert(varchar(30),Getdate(),121),'-','/')

--YYYY/MM/DD HH:MM:SS
Select Convert(varchar(10),Getdate(),111) + Space(1) + Convert(varchar(8),Getdate(),108)

--YYYYMMDDHHMMSS
Select Convert(varchar(10),Getdate(),112) + Replace(Convert(varchar(8),Getdate(),108),':','')

출처 : http://kuaaan.tistory.com/120


 얼마전에 개발서버에서 HDD가 가득찬 적이 있었습니다. 알고 보니 .mdf 파일은 수백메가 수준인데 .ldf 파일이 무려 30기가가 넘게 쌓여 있더군요. shrink 문을 날려도 줄지도 않고... 게다가 일단 트랜잭션 로그파일이 차게 되면 insert, select, delete 등 select를 제외한 아무 작업도 되지 않습니다. HDD 공간을 확보해도 인덱스라도 한번 재구성하고 나면 금방 다시 차버립니다.


데이터베이스의 로그 파일이 꽉 찼습니다. 데이터베이스의 트랜잭션 로그를 백업하여 사용 가능한 일부 공간을 확보하십시오

 뭔짓을 해도 위와 같은 에러만 나죠. 아주 미칩니다. ㅋㅋ
 그래서... .ldf 파일 사이즈를 줄이는 방법을 구글링해서 해결하기는 했죠. 그런데... 갑자기 트랜잭션 로그란 놈이 뭐하는 놈인지 궁금하더라구요. 이렇게 막 지워도 되는건지 겁도 나고... 제가 업이 DBA가 아닌 개발자라... 평소에 이런 방면에 대해서는 잘 몰랐거든요. 그래서 하루저녁 정도 백업 관련 자료를 찾아보면서 공부한 내용을 정리해 보았습니다.

1. SQL Server DBA가 수행해야 할 세가지 백업
 DB가 깨졌을 때를 대비하여 DBA는 다음의 세가지 백업을 수행해야 합니다.
1) Full Backup
말 그대로 풀 백업입니다. .mdf 파일에 들어있는 모든 데이터를 백업받죠.
그런데 풀백업이 이루어지는 동안에도 트랜잭션이 계속 진행되기 때문에 실제로는 아직 커밋되지 않은 작업이 백업시 포함될 수 있습니다. 나중에 이 백업을 리스토어했을 때 커밋되지 않은 데이터가 들어있다면 좀 이상해지겠죠? 그래서 실제로 풀백업을 받을 때는 현재 진행중인 트랜잭션에 대한 트랜잭션 로그도 함께 백업됩니다.
풀 백업이 중요한 것은, 풀 백업이 보관되어 있지 않다면 Differential Backup이나 트랜잭션 로그 백업을 아무리 열심히 받았어도 아무 소용이 없기 때문입니다.

HDD로 풀백업을 수행하는 SQL은 다음과 같습니다. (물론 GUI로도 가능합니다.)
  1. BACKUP DATABASE [DATABASENAME] TO DIST = 'C:\Temp\BackupFileName'  

만약 백업받을 파일을 백업장치로 등록하면 다음과 같이 간단하게 할 수 있습니다.
  1. EXEC sp_addumpdevice 'disk',   
  2.          '[BACKUPDEVICENAME]''C:\Temp\BackupFileName'  
  3. BACKUP DATABASE [DATABASENAME] TO [BACKUPDEVICENAME]  

2) Differential Backup (차등 백업? 차분 백업?)
이건 OS 백업받을 때의 Differential Backup과 유사합니다. "가장 마지막에 Full Backup 받은 이후의 변경 부분에 대한 백업"입니다. 마지막에 받은 Differential Backup 이후의 변경사항을 백업받는 것이 아닙니다. (SQL Server에는 Incremental Backup이란 개념이 없습니다.)
만약 10월 1일에 풀백업을 받은 후 10월 5일, 10일 15일에 Differential 백업 을 받았다면 DB를 15일자로 되돌리기 위해서는 10월 1일 풀백업을 Restore한 후 15일자 Differential 백업을 Restore하면 됩니다. (Intremental Backup과 달리 5일, 10일, 15일자를 모두 Restore할 필요가 없다는 거죠.)
  1. BACKUP DATABASE [DATABASENAME] TO [BACKUPDEVICENAME] WITH DIFFERENTIAL  

3) Transaction Log Backup (로그 백업)
트랜잭션 로그 백업에 대해 이해하려면 먼저 트랜잭션 로그란 놈에 대해서 이해를 해야겠죠?
트랜잭션 로그란 SQL Server에서 실행되는 모든 SQL문을 기록한 로그입니다. 어느 세션이 어떤 SQL을 실행했는지가 순차적으로 기록됩니다. 우리가 트랜잭션을 Rollback 시켰을 때 Begin Tran 시점 이전으로 되돌릴 수 있는 것은 트랜잭션을 시작한 이후의 모든 작업내용이 트랜잭션 로그에 기록되어 있기 때문입니다.
트랜잭션 로그는 다음과 같이 하여 백업받을 수 있습니다. (물론 GUI로도 가능합니다.)
  1. BACKUP LOG [DATABASENAME] TO [BACKUPDEVICENAME]  
 
로그 백업은 위의 데이터 백업과는 다른 몇가지 특성이 있습니다.

① 일단 백업된 트랜잭션 로그는 자동으로 삭제됩니다. 이때 ldf파일 사이즈가 줄어들지는 않지만 ldf 내에서 로그가 삭제되기 때문에 해당 ldf 파일에는 새로운 로그를 기록할 수 있는 빈 공간이 확보됩니다. 따라서, 주기적으로 트랜잭션 로그를 백업받으면, 별도로 로그를 삭제하지 않더라도 ldf 파일이 계속 커지는 것을 방지할 수 있습니다.

② 트랜잭션 로그는 가지고 있는 최신 풀백업 혹은 풀백업 + DifferentialBackup 세트로 부터 복원을 원하는 시점까지의 모든 백업본이 존재하지 않으면 아무 의미가 없습니다. 백업받은 로그 중 한 세트라도 분실하면 소용 없다는 의미입니다. 물론 풀백업을 한번도 받은적이 없다면 트랜잭션 로그는 소용없습니다.

③ 트랜잭션 로그가 온전하다면 Fault가 발생한 Database를 Fault 발생 직전의 시점으로 복원할 수 있습니다. 또한, 특정 시점으로의 Rollback 등 미세한 복원이 가능합니다.

  ※ 파일 백업은... 논외로 치겠습니다. ^^;


2. 트랜잭션 로그를 이용한 데이터 복원

트랜잭션 로그를 구체적으로 어떤 식으로 써먹을 수 있는지 두가지 예를 들어 살펴보겠습니다.

  1) 장애 시점까지의 DB 복구
다음과 같이 백업을 받고 있습니다.
① 10월 1일 DB Full Backup
② 10월 5일 Differential Backup
③ 10월 7일 Transaction Log Backup
④ 10월 9일 Differential Backup
⑤ 10월 10일 Transaction Log Backup
⑥ 10월 11일 Transaction Log Backup

만약 10월 12일에 DB에 Fault가 발생했다고 가정하겠습니다.
Q : DB를 Fault 발생 시점으로 완전하게 복구할 수 있을까요?
A : Yes~! .ldf파일의 트랜잭션 로그만 손상되지 않았다면 가능합니다.
복구 절차는 다음과 같습니다.

  • 현재 활성화된 트랜잭션 로그를 백업
  • 가장 최근에 수행한 전체 데이터베이스 백업을 복원
  • 차등 백업이 있으면 가장 최근의 것을 복원
  • 가장 최근에 차등 또는 전체 데이터베이스를 백업한 후에 만든 트랜잭션 로그 백업을 모두 차례대로 적용
  • 가장 최근에 로그를 백업한 후에 변경된 사항을 모두 수동으로 다시 실행

  • 위의 케이스에서는 다음과 같이 되겠지요.

    ① Fault가 발생한 시점의 트랜잭션 로그를 백업
    ② 10월 1일자 DB Full Backup을 Restore
    ③ 10월 9일자 Differential Backup을 Restore
    ④ 10월 10일자 트랜잭션 로그를 Restore
    ⑤ 10월 11일자 트랜잭션 로그를 Restore
    ⑥ ①에서 백업받은 트랜잭션 로그를 Restore

    Fault 발생지점까지 복원시키는 자세한 방법은 여기를 참고하세요.


      2) 특정 시점까지의 장애복구 (STOPAT)
    10월 12일에 실수로 중요 테이블을 Delete 시켰다고 가정합니다. 혹은 Update 하다가 실수로
    Where 절을 깜빡잊고 안적었다던지.. 하여간... 이런 상황. 백업받은 상황은 위와 동일하다고 가정합니다. 

    이러한 경우에도 복원이 가능할까요?
    넵! 트랜잭션 로그를 복원할 때는 "STOPAT"이라는 옵션을 통해 특정 시점까지만 복원이 가능합니다.

    문제가 발견된 시간을 기록하고, 해당 DB를 중지시킨 후 즉시 트랜잭션 로그를 백업받음
    ② 10월 1일자 DB Full Backup을 Restore
    ③ 10월 9일자 Differential Backup을 Restore
    ④ 10월 10일자 트랜잭션 로그를 Restore
    ⑤ 10월 11일자 트랜잭션 로그를 Restore
    ⑥ ①에서 백업받은 트랜잭션 로그를 "STOPAT" 옵션을 주어 ①에서 기록한 시간 직전까지만 Restore함.

    ⑤에 해당하는 작업은 다음과 같이 하면 됩니다.
    1. RESTORE LOG [DATABASENAME]  
    2. FROM  [BACKUPDEVICENAME]  
    3. WITH FILE = 3, STOPAT = '2009-10-15 14:15:23' , RECOVERY  

    지정 시간까지 복원시키는 방법에 대한 자세한 내용은 여기를 참고하세요.

    위의 SQL 문 중에서 FILE=3 이라는 옵션은 "LogBackupDeviceName"이라는 백업 디바이스의 백업세트 중 세번째 파일을 이용해 백업하라는 의미입니다. 백업 세트 내에 들어있는 파일 목록을 확인하는 방법은 다음과 같습니다.
    1. RESTORE FILELISTONLY FROM [BACKUPDEVICENAME];  
    RESTORE 문의 옵션에 대한 자세한 내용은 여기를 참고하세요. 


    3. 트랜잭션 로그를 삭제하여 로그파일(*.ldf 파일) 사이즈 줄이기

     위에서 얘기한 바와 같이 트랜잭션 로그를 백업받으면 자동으로 트랜잭션 로그가 삭제됩니다. 하지만 평소에 트랜잭션 로그를 백업받지 않던 DB서버에서 HDD 가 가득 찼다던지... 하면 트랜잭션 로그를 백업받을 여유가 없을 뿐더러... 무엇보다도 트랜잭션 로그를 삭제한다고 해서 무조건 .ldf 파일 사이즈가 줄어들지는 않는다는 것이 문제입니다. ^^

     트랜잭션 로그를 백업받지 않고 파일 사이즈를 줄이는 방법은 다음과 같이 두 단계로 이루어집니다.

    1) 로그 삭제 (BACKUP LOG ~)
     .ldf 파일 내에서 로그를 삭제합니다. 
     위에서 얘기한 바와 같이 "BACKUP LOG" 문을 실행하면 트랜잭션 로그를 백업한 후 자동으로 로그를 삭제하지만, 다음과 같은 옵션을 주면 백업받지 않고 로그만 삭제할 수 있습니다.
    1. DBCC SQLPERF(LOGSPACE) -- 현재 로그파일의 상태를 확인한다.  
    2. BACKUP LOG [DATABASENAME] WITH NO_LOG  -- 실제로 로그를 삭제하는 명령  
    3. --BACKUP LOG [DATABASENAME] WITH TRUNCATE_ONLY 위의 SQL과 동일한 효과  

    2) 로그파일 축소 (DBCC SHRINK~~)
     .ldf 파일의 사이즈를 축소합니다.
     위의 로그 삭제 작업은 ldf 파일 내에서 로그를 삭제하여 공간을 확보하지만 정작 ldf 파일의 사이즈는 줄어들지 않기 때문에 HDD의 여유공간을 확보하지 않습니다. 로그를 삭제한 후 아래와 같이 로그 파일에 대해 SHRINK 작업을 수행하면 위에서 삭제한 트랜잭션 로그의 공간만큼 실제로 ldf 파일을 축소시켜 HDD의 공간이 확보됩니다.
    1. SP_HELPDB [DATABASENAME] -- 대상 파일이름 확인 (name 컬럼)  
    2. DBCC SHRINKFILE([LOGFILENAME], 5, TRUNCATEONLY) -- 5MB까지 파일을 축소  
    3. -- DBCC SHRINKFILE(DBName_log, 5, TRUNCATEONLY) -- 보통은 이렇게...  
     
     위에서 얘기했듯이, 트랜잭션 로그는 풀백업 시점에서부터 장애 시점까지의 모든 로그가 보관되어 있지 않다면 소용이 없기 때문에, 로그파일을 삭제한 후 장애가 발생하면 장애 시점까지의 복원이 불가능해집니다. 따라서, 트랜잭션 로그를 삭제하여 HDD 공간을 확보한 후에는 반드시 풀 백업을 새로 받는 것이 좋습니다.

     로그를 삭제하지 않고 무조건 SHRINK DATABASE를 한다고 해서 ldf파일의 공간이 줄어들지는 않습니다. 왜냐하면, "SHRINK 는 불필요한 공간을 정리하는 작업"이기 때문입니다. 디스크 조각모음을 시킨다고 해서 필요한 로그를 마음대로 삭제해 버리면 안되겠죠? ^^

     다음과 같은 경우에는 SHRINK 작업을 수행하면 트랜잭션 로그가 삭제되고, .ldf 파일이 축소됩니다. 즉, SQL Server는 다음의 세 가지 경우에는 남아있는 트랜잭션 로그를 무용지물이라고 판단합니다. 세가지 경우의 상황에서 장애가 발생했다고 상상해보세요. 트랜잭션 로그가 있어도 장애 복구에 도움이 되지 않는 다는 것을 알 수 있습니다.
     반대로 다음의 세가지 중 한가지 경우에도 해당이 안된다면 SHRINK 작업을 수행하더라도 .ldf 파일의 사이즈가 줄어들지 않습니다. 왜? 이 트랜잭션 로그가 장애 복구에 필요할 수도 있기 때문이죠. 

    ① BACKUPLOG 문으로 로그를 지운 경우 : 이미 로그가 백업되었고, 백업된 로그는 내부적으로 삭제되기 때문에 .ldf 파일이 축소될 수 있습니다. WITH NO_LOG 옵션을 준 경우도 마찬가지입니다.
    ② 복구모델이 SIMPLE인 경우 : 복구모델이 SIMPLE이라는 것은 현 시점의 트랜잭션 로그가 보관되지 않는다는 의미이기 때문에 지나간 트랜잭션 로그도 소용 없다고 판단할 수 있습니다. 
    ③ 한번도 DATABASE 풀백업을 받은 적이 없는 경우 : 풀백업이 없다면 트랜잭션 로그 보관은 의미가 없습니다.

    4. SQL Server의 복구 모델
    SQL Server에서는 다음의 세가지 복구모델을 지원합니다. 이 복구모델에 따라 트랜잭션 로그를 기록하고 보관하는 방식이 달라집니다.

    1) 전체 (Full)
    모든 작업에 대해 트랜잭션 로그가 기록되고, 필요시 복원하거나 원하는 시점까지 복원이 가능합니다. 기본 설정이며, 로그가 가장 많이 기록되고 성능은 가장 떨어집니다.
    2) 대량로그 (Bulk Log)
    전체 모델과 거의 유사하나 대량의 로그가 기록되는 다음의 작업들에 대해 로그를 남기지 않기 때문에 로그가 더 적게 남고, 성능이 전체 모델보다 더 높습니다.
    . SELECT INTO
    . BCP 혹은 BULK INSERT
    . CREATE INDEX 혹은 INDEXED VIEW
    . TEXT 및 이미지 작업
    3) 단순 (Simple)
    단 순 복구모델에서는 CheckPoint (DBMS가 메모리와 HDD 의 Sync를 맞추는 시점) 발생시마다 Sync 후 트랜잭션 로그를 삭제합니다. 따라서, 트랜잭션 로그를 사용한 DB 복원이 불가능하며, 장애 발생시 풀백업 혹은 Differential 백업을 받은 시점까지만 복원이 가능합니다. (BACKUP LOG 문도 실행되지 않습니다.)
    만약 DB를 백업받지 않는 서버라면 (장애나면 데이터 포기?? ^^) 단순 복구모델로 설정해도 좋을 듯 합니다. 어차피 풀백업이 없으면 트랜잭션 로그도 소용 없으니까요.

    현재 운영중인 DB의 복구모델을 변경할 때는 각 복구모델을 변경한 후에 장애가 발생해도 복구가 가능하도록 하기 위해 복구모델 간의 관계를 잘 따져보아야 하는데 이부분에 대한 자세한 내용은 여기를 참고하세요.


    'DATABASE' 카테고리의 다른 글

    [펌] UNION과 UNION ALL 의 차이 및 주의 사항  (0) 2014.02.28
    TRUNCATE  (0) 2013.09.25
    CRUD 의 중요도?  (0) 2013.08.02
    DECODE, RANK()OVER(), UNION/UNION ALL  (1) 2013.08.02
    DATA BASE _ 기초  (0) 2013.07.10

    출처 - http://blog.danggun.net/1036


    이전 글에서 테이블변수에 대해서 이야기를 했었습니다.
    임시테이블과 테이블변수는 사용하는 방법면에서는 별차이가 없으나 성능상 차이가 있다고 합니다.
    테이블 변수가 성능면에서 더 유리하다고 하는데....직접 비교는 해보지 않아서 잘 모르겠습니다 ㅎㅎㅎ
    (참고 : [MSSQL] 저장프로시저에서 테이블(Table) 변수 사용하기)

    그런이유로 테이블 변수를 더 권장하고 있으나....임시 테이블을 사용하는 방법도 알려드리겠습니다 ㅎㅎ


    1.선언

    선언 임시테이블이므로 크래딧테이블(Create Table)로 생성하면 됩니다.


    1
    2
    3
    4
    5
    --리턴값을 받기위한 임시 테이블
    --Create Table [생성할 테이블 이름] ( [컬럼명] [데이터형], ... , [컬럼명] [데이터형] )
    Create Table #Result ( nIndex int
            , sName varchar(16)
            , sID varchar(16))


    2.입력
    입력은 테이블변수와 마찬가지로 인서트(Insert)를 이용하면 됩니다.

    1
    2
    3
    4
    --Insert [임시테이블] Exec [sql문]
    Insert #Result Exec ProcTest @nIndox
                , @sName
                , @sID


    3.사용
    임시테이블도 일반적인 테이블 처럼 사용할 수 있습니다.

    1
    Set @nTemp = (Select * From #Result)


    으앙 정신없다. 오랜만에 MSSQL , 아 진짜 DTG때문에 죽겠다. 꿈에서도 작업함ㅋㅋ


    하루의 데이터를 정리해서 요약하는 프로시저가 도는데


    문자열 이나 이진 데이터 는 잘립니다.


    라는 문구와 함께 매번 프로시저가 종료되었다. 


    원인은 입력 테이블의 크기보다 큰 값을 넣으려고 해서.


    차량번호를 입력하는 VARCHAR(12) 짜리 열에 

    경기32바1111 과 같은 제대로 된 차량번호가 아닌 테스트용 임시 차량번호 테스트경기32바1111 을 넣으려고 하니 

    사이즈가 너무 커서 에러발생..


    그래서 테이블을 지워버리고 해당 열을 VARCHAR(20)으로 사이즈를 바꿔서 새로 만들었다. 

    해결끝.

    truncate ->this resets the entire table, is there a way via truncate to reset particular records/check conditions.

    For ex: i want to reset all the data and keep last 30 days inside the table.

    Thanks.

    share|improve this question

    No, TRUNCATE is all or nothing. You can do a DELETE FROM <table> WHERE <conditions> but this loses the speed advantages of TRUNCATE.

    share|improve this answer
    Thanks, assuming that condition, how do i keep last 10 days data and delete the rest (for say the table has 10 million records), in an optimized manner. – Sharpeye500 Sep 13 '10 at 22:20
    The speed from TRUNCATE is because it doesn't write to the logs – OMG Ponies Sep 13 '10 at 22:21

    The short answer is no: MySQL does not allow you to add a WHERE clause to the TRUNCATEstatement. Here's MySQL's documentation about the TRUNCATE statement.

    But the good news is that you can (somewhat) work around this limitation.

    Simple, safe, clean but slow solution using DELETE

    First of all, if the table is small enough, simply use the DELETE statement (it had to be mentioned):

    1. LOCK TABLE my_table WRITE;
    2. DELETE FROM my_table WHERE my_date<DATE_SUB(NOW(), INTERVAL 1 MONTH);
    3. UNLOCK TABLES;

    The LOCK and UNLOCK statements are not compulsory, but they will speed things up and avoid potential deadlocks.

    Unfortunately, this will be very slow if your table is large... and since you are considering using theTRUNCATE statement, I suppose it's because your table is large.

    So here's one way to solve your problem using the TRUNCATE statement:

    Simple, fast, but unsafe solution using TRUNCATE

    1. CREATE TABLE my_table_backup AS
          SELECT * FROM my_table WHERE my_date>=DATE_SUB(NOW(), INTERVAL 1 MONTH);
    2. TRUNCATE my_table;
    3. LOCK TABLE my_table WRITE, my_table_backup WRITE;
    4. INSERT INTO my_table SELECT * FROM my_table_backup;
    5. UNLOCK TABLES;
    6. DROP TABLE my_table_backup;

    Unfortunately, this solution is a bit unsafe if other processes are inserting records in the table at the same time:

    • any record inserted between steps 1 and 2 will be lost
    • the TRUNCATE statement resets the AUTO-INCREMENT counter to zero. So any record inserted between steps 2 and 3 will have an ID that will be lower than older IDs and that might even conflict with IDs inserted at step 4 (note that the AUTO-INCREMENT counter will be back to it's proper value after step 4).

    Unfortunately, it is not possible to lock the table and truncate it. But we can (somehow) work around thatlimitation using RENAME.

    Half-simple, fast, safe but noisy solution using TRUNCATE

    1. RENAME TABLE my_table TO my_table_work;
    2. CREATE TABLE my_table_backup AS
         SELECT * FROM my_table_work WHERE my_date>DATE_SUB(NOW(), INTERVAL 1 MONTH);
    3. TRUNCATE my_table_work;
    4. LOCK TABLE my_table_work WRITE, my_table_backup WRITE;
    5. INSERT INTO my_table_work SELECT * FROM my_table_backup;
    6. UNLOCK TABLES;
    7. RENAME TABLE my_table_work TO my_table;
    8. DROP TABLE my_table_backup;

    This should be completely safe and quite fast. The only problem is that other processes will see tablemy_table disappear for a few seconds. This might lead to errors being displayed in logs everywhere. So it's a safe solution, but it's "noisy".

    Disclaimer: I am not a MySQL expert, so these solutions might actually be crappy. The only guarantee I can offer is that they work fine for me. If some expert can comment on these solutions, I would be grateful.

    share|improve this answer


    출처 : http://stackoverflow.com/questions/3704834/truncate-with-condition


    TRUNCATE DATABASE 2013. 9. 25. 15:03

    TRUNCATE

    설명

    TRUNCATE 문은 명시된 테이블의 모든 레코드들을 삭제한다.

    내부적으로 테이블에 정의된 모든 인덱스와 제약 조건을 먼저 삭제한 후 레코드를 삭제하기 때문에, WHERE 조건이 없는 DELETE FROM table_name 문을 사용하는 것보다 빠르다. TRUNCATE 문을 사용해서 삭제하면 ON DELETE 트리거가 활성화되지 않는다.

    대상 테이블에 PRIMARY KEY 제약 조건이 정의되어 있고, 이 PRIMARY KEY를 하나 이상의 FOREIGN KEY가 참조하고 있는 경우에는 FOREIGN KEY ACTION을 따른다. FOREIGN KEY의 ON DELETE 액션이 RESTRICT나 NO ACTION이면 TRUNCATE문은 에러를 반환하고, CASCADE이면 FOREIGN KEY도 함께 삭제한다. TRUNCATE 문은 해당 테이블의 AUTO INCREMENT 컬럼을 초기화하여, 다시 데이터가 입력되면 AUTO INCREMENT 컬럼의 초기값부터 생성된다.

    구문

    TRUNCATE [ TABLE ] <table_name>

    • table_name : 삭제할 데이터가 포함되어 있는 테이블의 이름을 지정한다.
    예제

    CREATE TABLE a_tbl(A INT AUTO_INCREMENT(3,10) PRIMARY KEY);

    INSERT INTO a_tbl VALUES (NULL),(NULL),(NULL);

    SELECT * FROM a_tbl;

     

    =============

                3

                13

                23

     

    --AUTO_INCREMENT column value increases from the initial value after truncating the table

    TRUNCATE TABLE a_tbl;

    INSERT INTO a_tbl VALUES (NULL);

    SELECT * FROM a_tbl;

     

    =============

                3