블로그 이미지
보미아빠

카테고리

보미아빠, 석이 (532)
밥벌이 (16)
싸이클 (1)
일상 (1)
Total
Today
Yesterday

달력

« » 2025.12
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31

공지사항

최근에 올라온 글


스터디에서 아래 내용을 자세히 함 파 드리겠습니다.~

Posted by My Name IS Kyou Hwa DAP 님께서 작성한 포스트 입니다.

-- 아래 -


microsoft mvp 김정선 강사님이 발표한 세미나 입니다.
블로그에서 보던 대로 후덕한 이미지와 구수한 입담이 아주 재미졌습니다.

1부. 향상된 혹은 새로운 Query Optimizing 기능
 - 실행계획 표시 정보 풍부

  2000, 2005, 2008로 진화 하면서 점점 더 많은 정보를 포함하기 때문에 프로파일러 확인 시 반드시 실행계획 보기를 끄고 측정 해야합니다.

 - 검색수(SCAN COUNT, 인덱스, 테이블 엑세스 카운트)
  현재까지 2008의  검색수는 비정상적으로 나옴, 신경 끄도록 하자!!
 
 - FORCESEEK 힌트
  조건절에 다음과 같이 조회할 경우, 2008 이전에는 인덱스를 탈 수 없었다.
  WHERE OrderID <= (1111+3)
  하지만 2008 부터 FORCESEEK 힌트는 사용가능한 임의의 인덱스에 대해 SEEK 로 탐색 가능

  SELECT *
  FROM dbo.order WITH (FORCESEEK)
  WHERE OrderID <= (1111+3)
  -> IN, LIKE 검색 시 또는 뷰테이블에 대해서도 SEEK 검색 할 수 있도록 도와줌..
      아직까지 특정 인덱스에 대해 FORCESEEK를 타도록은 할수 없다.(옵티마이저 맘대로..)


 - 조건절 매개변수의 선택도 기준
  매개변수로 조회할 경우 런타임 이전에는 변수값을 알수 없기 때문에 통계정보를 이용할 수 없었다.

  로컬변수와 OPTION ( OPTIMIZE for UNKNOWN ) 힌트 사용 시 통계정보를 이용하여 실행계획 작성
  DECLARE @0 VARCHAR(100) --로컬변수 사용해야함!!
  SELECT * FROM ORDER WHERE CUSTOMERID = @0 OPTION ( OPTIMIZE for UNKNOWN )
  ※DBCC FreeProccache : 실행계획 캐쉬 초기화

 - Query hint에서 Table Hint 허용, 2008부터 지원. 좋다 ^^

  SELECT *
  FROM ORDERS
  WHERE ORDERDATE <= '20090101'
  OPTION (TABLE HINT(ORDERS, INDEX(ORDERDATE)))

exec sp_create_plan_guide
@name='tbhint_4',
@stmt='SELECT o.OrderID,od.OrderID,o.OrderDate,o.EmployeeID FROM Orders o JOIN [OrderDetails] od ON o.OrderId=od.OrderId WHERE o.EmployeeID=1',
@type='SQL',
@module_or_batch=null,
@params=null,
@hints='OPTION (TABLE HINT(o,FORCESEEK), TABLE HINT(od,FORCESEEK))';
go

exec sp_control_plan_guide 'ENABLE','tbhint_4'

SELECT o.OrderID,od.OrderID,o.OrderDate,o.EmployeeID FROM Orders o JOIN [OrderDetails] od ON o.OrderId=od.OrderId WHERE o.EmployeeID=1

OPTION (TABLE HINT (table_alias1, hint1), (table_alias2, hint2)...)






 - Plan Guide 에서 Tabie Hint 활용
  Plan Guide 첨 들어본 녀석.. 요점인 즉은 Plan Guide 에 특정 쿼리에 대한 실행계획에 영향을 미칠 요소들을 등록 후 런타임 시 가이드 역할을 함
  EXEC SP_CREATE_PLAN_GUIDE
  @name = N'Guide3', -- 플랜 명
  @stmt = N'SELECT *
  FROM dbo.Orders AS om
  WHERE OrderDAte <= ''19970101'';',
  @type = N'SQL',
  @module_or_batch = NULL,
  @params = NULL,
  @hints = N'OPTION (TABLE HINT (om, INDEX(OrderDate)))'; --테이블 힌트 적용

 - 대량 INSERT 작업 Tx Log(트랜잭션 로그) 최소화
  INSERT INTO dbo.t_heap WITH (TABLOCK) -- 트랜잭션 로그 기록 생략,
  SELECT * FROM dbo.t_source

 - Partitioning - 파티션 인식 Seek 연산자
  2005의 경우 Constant Scan이라는 파티션 위치를 찾는 연산자가 선행 됐지만
  2008은 Constant Scan 생략(파티션 정보를 어딘가에서 저장하고 있다나.. 잘 모르겠심)

 - Partitioning - Lock Escalation 동작
  2005, 2008 디폴트는 테이블 (LOCK_ESCALATION = TABLE) 이다.
  테이블 업데이트 시 전체 테이블 락 발생..
  2008에서 ALTER TABLE mytable SET (LOCK_ESCALATION = AUTO), 특정 파티션에만 락이 발생.

 - Filtered Index - 매개변수 쿼리 이슈
  
특정구간만 인덱스 사용하고자 할 경우 사용하며 
  예) NULL이 많은 컬럼의 경우 유용 할듯.. 
  현재(2009.12,08)까지 AND, OR, IN  연산자들 중복사용은 할수 없음
  매개변수나 프로시저에서 사용 시 UnmatchedIndexes 발생
  
  CREATE NONCLUSTED INDEX NC_PRODUCT_ACC
  ON PRODUCTITON.PRODUCT(PRODUCTSUBCATEGORYID)
  WHERE PRODUCTSUBCATEGORYID >= 27
    AND PRODUCTSUBCATEGORYID <= 30

 - Plan Freezing
  특정 쿼리의 실행계획 고정 하는 방법, 자세히 하는 방법 웹에서 검색해 보시라. ㅜㅜ
  Exec sp_create_plan_guide_from_handle
    @name = '...' -- 오브젝트명
    @plan_handle = 0x06000E... -- 실행캐쉬 메모리 주소
    @statment_start_offset = ...

 - Plan Guide 보기 
 
SELECT msgnum, serverity, state, message
  FROM sys.plan_guides
  CROSS APPLY fn_validate_plan_guide(plan_guide_id)

 - Plan Cache 오용고찰
  adhoc 쿼리 수,  재사용안된 adhoc 쿼리 수를 통해 부분별한 adhoc 쿼리 발견 할 수 있다.
  ->매개변수 쿼리로 수정해야만 함
  adhoc 쿼리 수
   select objtype, count(*)
   from sys.dm_exec_cached_plans
   cross apply sys.dm_exec_sql_text(plan_handle) 
   where cacheobjtype = 'compiled plan'
   group by objtype

  재사용안된 adhoc 쿼리 수
   select objtype, count(*)
   from sys.dm_exec_cached_plans
   where cacheobjtype = 'compiled plan' and usecounts = 1
   group by objtype

 - optimize for ad hoc workloads 서버 옵션, 2008 부터 지원
  adhoc 쿼리가 최초 실행될 경우 compiled plan stub, 2번째 사용될 경우 비로소 plan cache에 기록

 - 유사쿼리 검색기능, 왕눈이(김정선 작품) 깔면 유사 기능 포함되어 있음
  SELECT TOP 5 query_stats.query_hash AS "Query Hash",
    SUM(query_stats.total_worker_time) / SUM(query_stats.execution_count) AS "Avg CPU Time",
    MIN(query_stats.statement_text) AS "Statement Text",
    COUNT(*) "similar_query_count"
  FROM
    (SELECT QS.*,
    SUBSTRING(ST.text, (QS.statement_start_offset/2) + 1,
    ((CASE statement_end_offset
        WHEN -1 THEN DATALENGTH(st.text)
        ELSE QS.statement_end_offset END
            - QS.statement_start_offset)/2) + 1) AS statement_text
     FROM sys.dm_exec_query_stats AS QS
     CROSS APPLY sys.dm_exec_sql_text(QS.sql_handle) as ST) as query_stats
  GROUP BY query_stats.query_hash
  ORDER BY 4 DESC;

2부. 재미있는 이슈들
 - Date 및 Time - 흥미로운 동작
  where convert(DATE, OrderDate) = '20020101'; -> DATE로 형변환 하는 좌변 가공의 경우 인덱스 처리 됨

 - Index Ordered Scan vs Allocation Ordered Scan
  클러스터 인덱스가 있는 테이블의 경우,
  select * from order; 와 같이 검색할 경우 등록순서대로 검색
  with(nolock) 으로 검색 시 할당 순서로 액세스가 되며 조각화가 심할 경우 데이터 무결성 보장하지 못함

 - OPTION (RECOMPILE) hint
  만능쿼리 조회 시 아래와 같이 조회 할 경우 런타임 전에는 매개변수의 값을 알수 없으므로 정상적인 인덱스를 탈수 없다.
  where (orderid = @orderid OR @orderid is null)
    and (customerid = @customer OR @customerid is null)
    and (employeeid = @employeeid OR @employeeid is null)
  OPTION(RECOMPILE) -- 런타임전에 매개변수 값으로 컴파일 실행, 런타임 시 컴파일(SP1 + CU5 적용 시 정상 작동)


Posted by 보미아빠
, |

connect by

카테고리 없음 / 2011. 5. 3. 14:21



if object_id ('tblx') is not null
drop table tblx
go


create table tblx
(idx int identity(1,1)
,emp_name varchar(1000)
,parent_seq int
,seq int
)

go

insert into tblx values
 ('minsouk', null, 1)
,('ben gan', 1, 2)
,('Kollor', 2, 4)
,('Sarka', 4, 6)
,('Christian', 4, 8)
,('Justin', 2, 5)
,('Brent', 5, 7)
,('James', 1, 3)
,('Steven', 2, 9)

go

;with c_tblx as (
select 0 as emplevel
  , emp_name
     , parent_seq
     , seq
     , convert(varchar(100), ' / ' +cast(seq as varchar(100)))
       path_order -- siblings by
  from tblx
 where seq = 1  -- start with
 union all
select emplevel + 1
  , a.emp_name
     , a.parent_seq
     , a.seq
     , convert(varchar(100), b.path_order + ' / ' + cast(a.seq as varchar(100))) 
       -- siblings by
  from tblx a
  join c_tblx b
    on a.parent_seq = b.seq -- connect by prior
)
select replicate('  ', emplevel * 2) + cast(seq as varchar(100))
     , *
  from c_tblx
 order by path_order

 

Posted by 보미아빠
, |

Tree 관리 이슈가 있으면 Tree 를 관리 안하면 되고,
logging 디스크 이슈가 있으면 안하면 되고
tempdb 가 문제이면 풀면 되고,
page size 가 작으면 늘이면 되고,
optimization 을 더 열심히 해야 할 듯 하면 시키면 되고 문제가 있으면 해결하면 되지 머 어렵나?
OK? 힘내삼! 도우며 살거라....~

DW 성능 이슈 해결을 위해 사용 될 수 있는 자료

http://blogs.msdn.com/b/sqlserverstorageengine/archive/2008/10/24/new-update-on-minimal-logging-for-sql-server-2008.aspx

2301 Enable advanced decision support optimizations
834 large page allocation
610 minimal logging
845 lock page in memory
1118 tempdb

example
select count(*) from tblx option(querytraceon 2301)

Posted by 보미아빠
, |



--1. http://www.postman.pe.kr/zipcode/ 에서 3번 다운로드
--2. excel 에서 csv 로 변환 후 db insert

if object_id('tblx') is not null
drop table tblx
go

create table tblx
(
ZIPCODE varchar(1000)
,SIDO varchar(1000)
,GUGUN varchar(1000)
,DONG varchar(1000)
,RI varchar(1000)
,ST_BUNJI varchar(1000)
,ED_BUNJI varchar(1000)
,SEQ varchar(1000)
)
go

BULK INSERT l.dbo.[TBLx]
FROM '\\127.0.0.1\c$\db1\zipcode_20110311.txt'
WITH
(
FIELDTERMINATOR = ',',
TABLOCK,
FIRSTROW =2
)
go

delete from tblx where seq is null
go

--3. 모의 데이터 삽입
if object_id('tbly') is not null
drop table tbly
go

create table tbly
(idx int identity(1,1)
,h_address varchar(1000)
)
go

insert into tbly values ('서울특별시 강남구 논현1동 21번지')
insert into tbly values ('대구시 동구 신암4동 139번지')
insert into tbly values ('경기도 용인시 기흥구 중동 참솔마을 109동')
insert into tbly values ('경기 용인 기흥 중동 참솔마을')
insert into tbly values ('대구동구신암3동 어쩔시구리')
insert into tbly values ('이상한나라의 엘리스')
go

select top 3 * from tblx order by cast(seq as int)
select * from tbly

-- 원하는 데이터         
select sido, gugun, count(*) cnt
  from (select idx, h_address, zipcode, sido, gugun
    from tbly a
   cross apply (select top 1 *
      from tblx
        where a.h_address like +'%'+left(SIDO,2)+'%'+'%'+left(GUGUN,2)+'%') b ) a
 group by sido, gugun
go

-- 오류 데이터

select a.*
  from tbly a
  left join (select idx, h_address, zipcode, sido, gugun
     from tbly a
    cross apply (select top 1 *
       from tblx
       where a.h_address like +'%'+left(SIDO,2)+'%'+'%'+left(GUGUN,2)+'%') b ) b
    on a.idx = b.idx
 where b.idx is null

Posted by 보미아빠
, |

퀴즈

카테고리 없음 / 2011. 4. 23. 03:03


--dynamic 쿼리가 몹시 귀찮은 경우
--다른 컬럼으로 index 를 타고, 필터조건만 처리 할 경우 유용한 쿼리 로직

if object_id ('tblx') is not null
drop table tblx
go

create table tblx
(idx int
,c1 int
,c2 int
)
go

insert into tblx values(1,1,null),(2,null,2),(3,3,3), (4, null,null)

-- @c1 의 값이 null 이면 필터하지 않고, 값이 있으면 값으로 뿌린다.
-- 보통 다음과 같은 쿼리를 짜는데, 이는 null 값에 문제를 일으킨다.
-- 아래 문제를 해결하는 것이 미션 1 이다.

declare @c1 int = null

select *
  from tblx
 where c1 = case when @c1 is null then c1 else @c1 end
go

-- 해결방안

숙제임 (iq 90)

-- @c1 의 값이 9999 이면 필터하지 않고, 값이 있으면 값으로 출력하며, null 이면 null 만 출력한다. 
-- 이것이 미션 2 이다.

숙제임 (iq 100)

Posted by 보미아빠
, |

--dynamic 쿼리가 몹시 귀찮은 경우
--다른 컬럼으로 index 를 타고, 필터조건만 처리 할 경우 유용한 쿼리 로직

if object_id ('tblx') is not null
drop table tblx
go

create table tblx
(idx int
,c1 int
,c2 int
)
go

insert into tblx values(1,1,null),(2,null,2),(3,3,3), (4, null,null)

-- @c1 의 값이 null 이면 필터하지 않고, 값이 있으면 값으로 뿌린다.
-- 보통 다음과 같은 쿼리를 짜는데, 이는 null 값에 문제를 일으킨다.
-- 아래 문제를 해결하는 것이 미션 1 이다.

declare @c1 int = null

select *
  from tblx
 where c1 = case when @c1 is null then c1 else @c1 end
go

-- 해결방안

declare @c1 int = null

select *
  from tblx
 where (c1 = @c1 or 1=case when @c1 is null  then 1 else 0 end)
go

-- @c1 의 값이 9999 이면 필터하지 않고, 값이 있으면 값으로 출력하며, null 이면 null 만 출력한다. 
-- 이것이 미션 2 이다.

declare @c1 int = 9999

select *
  from tblx
 where (c1 = @c1 or 1=case when @c1 = 9999  then 1 else 0 end) or (c1 is null and 1=case when @c1 is null then 1 else 0 end)
go

-- 복합 필터 조건
declare @c1 int = null
declare @c2 int = null

select *
  from tblx
 where ((c1 = @c1 or 1=case when @c1 = 9999  then 1 else 0 end) or (c1 is null and 1=case when @c1 is null then 1 else 0 end))
   and ((c2 = @c2 or 1=case when @c2 = 9999  then 1 else 0 end) or (c2 is null and 1=case when @c2 is null then 1 else 0 end))
go

 select *
  from tbly
 where (a = @col1 or @col1 is null)

Posted by 보미아빠
, |

미시령 업힐~

카테고리 없음 / 2011. 4. 17. 23:07

난 평소 로드를 타면서 헬멧을 쓰지 않았다.
그런데 이날 대회라서 어쩔수 없이 헬멧을 착용했다. 그런데, 다운힐 후 시속 50 ~ 60 KM 로 달리는 상황에서 그 말로만 듣던 낙차를 할뻔 했다. 이날 바람이 어찌나 심하게 불던지 정말 휙 밀리더니 넘어질뻔 했다. 온몸에 식은땀.......
이날 이후는 헬멧을 꼭 착용한다. 봄이도 있고 여름이도 곧 나올 준비를 하고, 혹시나 낙차해 침 흘리고 살 수 없지 않는가...

Posted by 보미아빠
, |

EXEC sp_change_users_login 'Update_One', 'loginname', 'loginname'

create login loginname with password = 'password'
go

use northwind
go

create user loginname for login loginname
go

GRANT EXECUTE TO loginname
go

EXEC master..sp_dropsrvrolemember @loginame = N'coupon', @rolename = N'sysadmin'
EXEC master..sp_addsrvrolemember @loginame = N'coupon', @rolename = N'sysadmin'

에러는 이렇게 잡으세요~

create proc a
with execute as owner
as

select 'dynamic sql'
go





Denali ?
Denali 에서는 아래와 같은 기능이 추가 되었습니다.

Custom server roles

Mike Walsh blog post: http://bit.ly/AB_Denali_MikeWalsh
Posted by 보미아빠
, |


파일을 다운로드 해서


 


실행하시면 되고, 몇몇 변수는 수정해야 합니다.
purge_times 숫자만큼 남기고 모두 삭제 됩니다.
sql agnet 를 이용해 일정 시간 간격으로 백업 하시면 개발자나 DBA 혹은 예상치 못한 오류로 부터 개발코드를 지킬 수 있습니다.



결과는 다음과 같이 생성되고 purge_times 를 초과하면, 과거 폴더를 자동으로 삭제 합니다.
Posted by 보미아빠
, |

미러링

카테고리 없음 / 2011. 3. 26. 15:34


restore database mirrortest from disk ='c:\backup\full.bak'
with norecovery

restore log mirrortest from disk ='c:\backup\log.bak'
with norecovery


alter database mirrortest
set partner off

restore database mirrortest with recovery



http://social.msdn.microsoft.com/Forums/en/sqldatabasemirroring/thread/73fb15c0-9270-4cbf-a74e-544639e792da

SELECT type_desc, port FROM sys.tcp_endpoints;
SELECT name,role,state_desc FROM sys.database_mirroring_endpoints;

restore database JoyCoupon from disk ='C:\back\JOYDBSQLFB_JOYCOUPON_FFFFFFFFFF_20110327_203730.fbak'
with norecovery, password ='PRD00012323541234',
move 'matjoy' to 'd:\db\matjoy.mdf',
move 'matjoy_log' to 'c:\db\matjoy_log.ldf'
, replace
go

restore log JoyCoupon from disk ='c:\back\JOYDBSQLLB_JOYCOUPON_LLLLLLLLLL_20110327_203806.lbak'
with norecovery
go

restore log JoyCoupon from disk ='c:\back\JOYDBSQLLB_JOYCOUPON_LLLLLLLLLL_20110327_204000.lbak'
with norecovery
go





http://support.microsoft.com/kb/246133 2000 의 로그인 카피

http://support.microsoft.com/kb/918992 2005 이상의 경우 로그인 카피

sp_change_users_login 'Update_One', 'kindsaint','kindsaint'


-- ------------------------------------------------------------------------------------------------------------------------
-- 우리는 sql 2008 에서 2008r2 로 데이터베이스 미러링을 통해 업그레이드 하려고 한다.
-- ------------------------------------------------------------------------------------------------------------------------
-- 1. 같은 windows 계정으로 sql 을 스타트 시킨다.  ** 참고로 반드시 계정으로 스타트 시켜야 한다.
-- 2. 방화벽을 내린다. wf.msc 에서 모든 방화벽 제거 (혹은 mirroring endpoint port 만 open 우리는 7022)
-- 3. ping 이 가는지 test 한다. (양방향)
-- 4. endpoint 대상 포트로 telnet 테스트를 한다.  서버 관리자에서 telnet 기능을 활성화 한다. (시간이 좀 걸릴 수 도 있음) 
       endpoint 설정하고 할것...-_- 바봉....
-- 5. host 추가 한다. FQDN 으로 설정해야 한다.
-- 6. cmd 를 ctrl shift alt + enter 로 관리자 모드로 시작한 다음 sql alias 에 설정된 이름을 등록한다.
-- 7. notepad c:\windows\system32\drivers\etc\hosts 수정한다.
-- 8. sqlservermanager10.msc 에서 alias 는 32bit 64bit 모두 설정한다.
-- 9. 데이터베이스 이름에는 특수문자가 없어야 한다. ㅠ.ㅠ _ (언더바 있으면 에러난다. 씨봉)
-- ------------------------------------------------------------------------------------------------------------------------
-- 대상 데이터베이스 fullbackup
-- 대상 데이터베이스 logbackup 수행
--backup database minsouk to disk ='c:\backup\minsouk.full'
--backup log minsouk to disk ='c:\backup\minsouk_log.bak'
-- ------------------------------------------------------------------------------------------------------------------------
-- norecovery 모드로 log 까지 복구한다.
--restore database minsouk from disk ='c:\backup\minsouk.full'
--with norecovery,
--move 'minsouk' to 'c:\backup\minsouk.mdf',
--move 'minsouk_log' to 'c:\backup\minsouk_log.ldf'
--, replace
--go
--restore log minsouk from disk ='c:\backup\minsouk_log.bak'
--with norecovery
--go
-- ------------------------------------------------------------------------------------------------------------------------
--endpoint 확인하는 쿼리 2번째 쿼리의 결과로 나오는 name 이 미러링용 endpoint 이다.
--SELECT type_desc, port FROM sys.tcp_endpoints;
--SELECT name,role,state_desc FROM sys.database_mirroring_endpoints;
--drop endpoint endpoint_mirroring
-- 만약 삭제를 해야 한다면 drop endpoint endpointname
-- ------------------------------------------------------------------------------------------------------------------------
-- 양쪽 서버 ssms 에서 endpoint 생성
--CREATE ENDPOINT endpoint_mirroring
--STATE = STARTED
--AS TCP ( LISTENER_PORT = 7022 )
--FOR DATABASE_MIRRORING (ROLE=PARTNER, ENCRYPTION=DISABLED);
--telnet 에서 telnet bammabak 7022 하면 접속되면서 화면이 모두 사라진다. (정상적이면, 에러면, 에러떨어지지요)
--ALTER DATABASE minsouk
--SET PARTNER ='TCP://bammabak:7022'
-- ------------------------------------------------------------------------------------------------------------------------
-- 파트너 쪽에서 mirroring 제거시
--alter database minsouk
--set partner off
-- 복구시
--restore database minsouk with recovery
-- ------------------------------------------------------------------------------------------------------------------------
-- 삭제
--use master
--go
--alter database minsouk set single_user with rollback immediate
--go
--drop database minsouk
--go
-- ------------------------------------------------------------------------------------------------------------------------

 




restore headeronly from disk ='G:\mirror_init\CYBERSQL_SQLFB_BANK_FFFFFFFFFFFFFFF_20110817_004805.fbak'
with password ='D'

restore filelistonly from disk ='G:\mirror_init\CYBERSQL_SQLFB_BANK_FFFFFFFFFFFFFFF_20110817_004805.fbak'
with password ='D'

restore database bank from disk = 'G:\mirror_init\CYBERSQL_SQLFB_BANK_FFFFFFFFFFFFFFF_20110817_004805.fbak'
with norecovery ,
move 'bank' to 'E:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\DATA\bank.mdf',
move 'bank_log' to 'F:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\Data\bank_log.ldf',
password = 'D'

restore log bank from disk ='G:\mirror_init\CYBERSQL_SQLLB_BANK_LLLLLLLLLLLLLLL_20110817_005812.lbak'
with norecovery








 

Posted by 보미아빠
, |

최근에 달린 댓글

최근에 받은 트랙백

글 보관함