제2의 비엔지니어 인생관을 꿈꾸며

Posted
Filed under MSSQL
MSSQL 의 대용량 데이터 관리를 위한 파티셔 테이블 에 대해서  시나리오 별로 작성해 보았다.
우선 파티셔닝에 대해 왜 필요한지 어떤게 장점이고, 단점인지 뭔지, 뭐하는건지에 대한 내용은 설명되어있지 않다. 간략하게 설명 드리자면, 대용량 데이터 베이스 환경에서, 데이터가 관리되는, 최소규모의 테이블을 물리적 & 논리적 분할을 통해 I/O 및 기타 성능을 높이는데 목적이 있다. 자세한건 구글링을 통해 알아보도로 하고, 다음 포스팅에 다시한번 파티셔닝을 다룰때 이야기 하도록 하자



포스팅의 내용을 살펴보면,
# DB 생성 또는  기존 DB 에 그룹 추가 후 그룹별 파티셔닝하기 (Primary 1개 + 그룹 5개)
   >  쿼리 연습겸 , 3개는 Create DATABASE 로 나머지 2개는 Alter DataBase 로 처리
# 기본 DB 에 , 쿼리로 DB 에 파일 그룹 추가해 보기 (기존에 단일 그룹  > 그룹으로 추가하는 방법을 알수있음)
# 파티셔닝에 필요한  쿼리들을 알수있다. (Partition Function , Partion Scheme  , Create Table , Create Index )
# 파티셔닝  관리에 필요한 명령어 처리(SPLIT , MERGE , SWITCH)
| 자세한 내용은 상황 별로 설정하여 그때 그때 쿼리 및 이미지 주변에 설명에 두었으니, 참고하길 바랍니다.


DB 생성(그룹동시생성)  및 alter 명령어로 그룹추가
CREATE DATABASE partitionDB
ON
Primary  (Name = "partitionDB_PM" , FileName="D:\TEST_DATA\pDB_M.MDF"),  

FileGroup FG1 (name= "partitionDB_FG1" , FileName  ="D:\TEST_DATA\fDB_1.NDF") ,
FileGroup FG2 (name= "partitionDB_FG2" , FileName  ="D:\TEST_DATA\fDB_2.NDF") ,
FileGroup FG3 (name= "partitionDB_FG3" , FileName  ="D:\TEST_DATA\fDB_3.NDF") 


Alter DataBase [partitionDB] add FileGroup [FG4]
Alter DataBase [partitionDB] add File  (Name ="partitionDB_FG4", FileName = "D:\TEST_DATA\fDB_4.NDF") 
To FileGroup  [FG4]


Alter DataBase [partitionDB] add FileGroup [FG5]
Alter Database [partitionDB] add File (Name = "partitionDB_FG5", FileName = "D:\TEST_DATA\fDB_5.NDF") 
To FileGroup [FG5]


use partitionDB 


DBCC SHOWFILESTAT


파티션 함수생성
CREATE PARTITION FUNCTION [PF_For_Date_FG5] (datetime)
AS
RANGE LEFT FOR VALUES
(
            '2017-03-01 00:00:00' ,  -- 'RegDate 값' <= 2017-03-1 
            '2017-06-01 00:00:00' ,  -- 'RegDate 값' <= 2017-06-1 
            '2017-09-01 00:00:00' ,  -- 'RegDate 값' <= 2017-09-1
            '2017-12-01 00:00:00' ,  -- 'RegDate 값' <= 2017-12-1 
            '2018-03-01 00:00:00'    -- 'RegDate 값' <= 2018-03-1                      
  ) 

파티션 펑션  쿼리 확인
select * From sys.partition_functions
select * From sys.partition_range_values





파티션 스키마 생성
CREATE PARTITION SCHEME [PS_For_Date_FG5] 
AS 
PARTITION [PF_For_Date_FG5] To ([FG1], [FG2], [FG3], [FG4], [FG5])
*  스크립 생성하면 오류난다? 왜지? 그룹5개만들도 다 맞는데?
*   2018-03-1 <  이후 데이터가 들어갈곳이없다.
*  그래서 그룹생성시 파티셔닝할 그룹 + 1개(사실은 1개 이상) 그룹을 추가로 만들어야함


[FG6] 파일그룹 추가
ALTER DATABASE [partitionDB] add FileGroup [FG6]
ALTER DATABASE [partitionDB] add File (name = "partitionDB_FG6" , filename = "D:\TEST_DATA\fDB_6.NDF")

DBCC SHOWFILESTATS

| 오잉? 이상하다
| 방금만든 [partion_FG6] 이 Primary 와 같은 FileGroup 1 에 들어가있다 
| To FileGroup 옵션을 빼먹었다. --; 삭제하고다시하자

[FG6]  파일그룹을 만들고 & 물리적 파일을 [FG6] 그룹에 적재 
① [FG6]  파일그룹을 생성
Alter database [partitionDB] remove filegroup [FG6] -- 그룹  삭제
Alter database [partitionDB] remove file [partitionDB_FG6] -- 파일  삭제

ALTER DATABASE [partitionDB] add FileGroup [FG6]
ALTER DATABASE [partitionDB] add File (name = "partitionDB_FG6" , filename = "D:\TEST_DATA\fDB_6.NDF") To Filegroup [FG6]
 만약  그룹(TO Filegroup 그룹명) 으로 생성된 파일그룹 삭제시 ① FILE (*.NDF)를 삭제 후  ② FileGroup 을 순서대로
삭제되어야 한다. (논리적으로 [FG6] 안에 물리 파일인[partitionDB_FG6] 이 있기때문)

DBCC SHOWFILESTATS
 | FileGroup 7번을 정상적으로 할당 받았다



② 파티션 스키마에 [FG6]
CREATE PARTITION SCHEME [PS_For_Date_FG5] 
AS 
PARTITION [PF_For_Date_FG5] To ([FG1], [FG2], [FG3], [FG4], [FG5])


| 또 오류  왜 그러지?
| 방금 만든 [FG6] 를 추가해야한다.
| 기본 [FG1] ~ [FG5] 까지는 파티션 함수에서 지정한 조건에 맞는 데이터가 파티셔닝되고
| 그 외의 조건은 [FG6] 에 들어가도록,
| PARTITION SCHEME 생성시에는 PARTITION FUNCTION 지정한 그룹 갯수 + 1개 이상을 추가 해야 한다.



아래쿼리 정상처리
CREATE PARTITION SCHEME [PS_For_Date_FG5] 
AS 
PARTITION [PF_For_Date_FG5] To ([FG1], [FG2], [FG3], [FG4], [FG5] , [FG6])


테이블 생성 & 인덱스 생성시 파티셔닝 하기
Create table Tbl 
(
      idx int ,  
      RegDate datetime
)  ON PS_For_Date_FG5(regdate)
| 테이블에 인덱스 생성시 파티션용 스키마 적용 하여 테이블 파티셔닝 한다.



CREATE NONCLUSTERED INDEX IDX_DUMMY
ON Tbl (regDate)
ON PS_For_Date_FG5 (RegDate) 
| 위의 테이블 생성시 , 테이블에 인덱스 생성시 파티션용 스키마 적용 하여 테이블 파티셔닝 한다.
| 나는 일부러 넌클러스터 인덱스로 해보았다. 다음 포스팅에 파티션인덱스를 다룰때 3가지 "인덱스없이,넌클러스터,클러스터" 를 해보자


tbl에 더미 데이터 넣기
declare @i int
declare @d datetime
set @i = 1 
set @d = '2017-01-01'
BEGIN TRAN
WHILE @i <= 10000
Begin 
        set @i = @i + 1
        insert Tbl values (@i , dateadd(hh ,  @i , @d) )
End
COMMIT TRAN


분할된 파티션 정보를 그때 그때 눈으로 확인하기위해 아래 프로시져를 생성해두자
Create proc sp_partiton_view  -- drop proc sp_partiton_view
        @tbl varchar(50)
as
select 
        F.Name ,
        G.partition_number  , 
        G.Rows ,  
        E.value  
rom 
sys.destination_data_spaces A
        left outer join sys.indexes B on A.partition_scheme_id = B.data_space_id 
        left outer join sys.tables C  on B.object_id = C.object_id
        left outer join sys.partition_schemes D on B.data_space_id = D.data_space_id 
        left outer join sys.partition_range_values E on E.function_id = D.function_id and E.boundary_id = A.destination_id
        left outer join sys.filegroups F on F.data_space_id = A.data_space_id  
        left outer  join sys.partitions G on G.object_id = C.object_id and  G.index_id = B.index_id 
        
                                                        and G.partition_number = A.destination_id
where C.name = @tbl and B.name is not null order by partition_number asc



위에 만들어지 프로시져를 한번 써서, 파티션별로 들어간 데이터 갯수 눈으로 확인해보자
sp_partiton_view 'tbl'

기존 (파티셔닝기준) 데이터로  파티션 위치 확인
SELECT $PARTITION.[PF_FOR_DATE_FG5] ('2017-06-01') 
SELECT $PARTITION.[PF_FOR_DATE_FG5] ('2018-07-01') 
| '2017-06-01' 날짜로 PF_For_Date_FG5 파티션 평션 적용시켜 insert 하면  몇번째 Partition_number 로 들어갈까?
| '2018-07-01' 날짜로 PF_For_Date_FG5 파티션 평션 적용시켜 insert 하면  몇번째 Partition_number 로 들어갈까?
 결과는 아래와 같다.






파티션 SPLIT ①

" 새로운 파티션 추가 #1
시나리오 :  새로운 그룹 [FG7] 생성 후 2018-06-01 추가 "

추가전, 현재 상태를 먼저 확인해보자
sp_partiton_view 'tbl'

| 현재 파티셔닝된 상태 확인

새로 추가될 그룹 추가 생성
ALTER DataBase [partitionDB] add filegroup [FG7]
ALTER database [partitionDB]  add File (Name = "partitionDB_FG7", FileName = "D:\TEST_DATA\fDB_7.NDF") To FileGroup [FG7]

파티션 스키마에 추가 다음으로 파일그룹 FG7 지정
ALTER PARTITION SCHEME PS_For_Date_FG5 Next USED [FG7]
ALTER PARTITION FUNCTION PF_For_Date_FG5()  SPLIT RANGE('2018-06-01 00:00:00') -- 함수명뒤에 '()' 없으며 구문 오류남
| 파티션 평션에 부합되지않은 [FG6] 에 있던 데이터들 중 추가된 파티션 정보에 부합되는 정보가 있으면
| 그쪽 그룹으로 데이터가 이동하는 작업이(삭제/입력 I/O발생 나머지는 그대로 잔류




추가된 Partition_number 6 : [FG7] 확인
sp_partiton_view 'tbl'
| 새로운 파티션 스키마 정보가 삽입되면서 partition_no:6 에서 -> partition_no : 7 로 밀림

제대로 분할되었는지 테스트 INSERT
insert tbl values(10001 , '2018-04-01') -- 2번  실행
insert tbl values(10001 , '2018-06-01') -- 3번 실행



sp_partiton_view 'tbl'




파티션 SPLIT ②

 새로운 파티션 추가 #2
시나리오 : 기존에 파티션정보에 이미 '2017-01-01' 이 사용중인 [FG1] 를 다른 조건으로 파티셔닝하기
[FG6] 은 기존에 위의 조건 외의 데이터가들어가는 그룹이었다  "
 ALTER PARTITION SCHEME PS_For_Date_FG5 Next USED [FG1]
    ALTER PARTITION FUNCTION PF_For_Date_FG5()  SPLIT RANGE('2018-09-01 00:00:00') 
추가된 Partition_number 6 : [FG7] 확인
sp_partiton_view 'tbl'


insert tbl values(10001 , '2018-07-01') -- 2번 실행
insert tbl values(10001 , '2018-08-01') -- 4번 실행
sp_partiton_view 'tbl'




파티션 SPLIT ③

 새로운 파티션 추가 #3
시나리오 : 새로운 그룹 [FG8] 생성 후 2018-06-01 추가 "
ALTER DataBase [partitionDB] add filegroup [FG8]
ALTER database [partitionDB]  add File (Name = "partitionDB_FG8", FileName = "D:\TEST_DATA\fDB_8.NDF") To FileGroup [FG8]


스키마에 [FG8] 추가하고 범위 지정
ALTER PARTITION SCHEME PS_For_Date_FG5 Next USED [FG8]
ALTER PARTITION FUNCTION PF_For_Date_FG5()  SPLIT RANGE('2018-12-01 00:00:00')
sp_partiton_view 'tbl'

| 기본 그룹의 partitinu_number 가 다시 도 밀려나는걸 볼 수 있다.

insert tbl values(10001 , '2018-11-01') -- 4번 실행
insert tbl values(10001 , '2018-12-01') -- 5번 실행

sp_partiton_view 'tbl'




 파티션 MERGE
> 기존에 분할된 파티션 영역을 합친다.
> '2018-12-01 00:00:00.000' 조건을 가지고 있는 Partition_Num 8 (FG8)을 Merge(합침)
> 합쳤을때 데이터가 파티션 함수 조건에 맞는 데이터가 아니라면 기본 그룹에 INSERT 됨

 ALTER PARTITION FUNCTION PF_For_Date_FG5() MERGE RANGE ('2018-12-01 00:00:00.000')

sp_partiton_view 'tbl'


| Merge 한  파티션에 있던 데이터들('2018-12-01') 이  파티셔닝된 조건에 맞는 파티션이 없으므로,  
기본 파티션된 그룹 partition_number 8 인 [FG6] 에 들어감.
 

중간에 있는 2018-06-01 파티션을 Merge 해보자
ALTER PARTITION FUNCTION PF_For_Date_FG5() MERGE RANGE ('2018-06-01 00:00:00.000')
sp_partiton_view 'tbl'

| Merge 한  파티션에 있던 데이터들('2018-06-01') 이  파티셔닝된 조건에 맞는 파티션이 partition_number 6번에
있으므로, partition_number 6 인 [FG1] 에 들어감.
 



파티션 SWITCH 
> SWITCH 작업 전에 두 테이블이 존재해야 합니다..
> 파티션 SWITCH 조건을 MSDN 을 통해 찾아보면
   ①받는 파티션이 존재하되 비어 있어야 합니다.
   ②분할되지 않은 받는 테이블이 존재하되 비어 있어야 합니다
   ③파티션은 동일한 열에 있어야 합니다. 
   ④원본 및 대상 테이블은 동일한 파일 그룹을 공유해야 합니다. 


파티셔닝된 Tbl 의 구조를 확인하고  같은구조의 tbl_tmp 를 만든다.
(위의 조건을 무시하고 primary 그룹에 그냥 만들어보자)
select * from tbl
select * into tbl_tmp from tbl where idx = -1 -- 스키마만 복사
SWITCH 시작
 ALTER TABLE tbl SWITCH PARTITION 5 TO TBL_TMP


| 오류! SWITCH 하기위해 PARTITION_NUM 6 번 데이터를 tbl_tmp 로 switching 시도했으나 안됨
| ④ 원본 및 대상 테이블은 동일한 파일 그룹을 공유해야 합니다. 항목 위반
< 각각의 테이블 파티션 정보 & 테이블 정보 보기 >
원본 tbl  파티션된 정보보기
SELECT * FROM SYS.PARTITIONS where object_id = object_id('tbl')  
order by index_id  , partition_number 


타켓 tbl_tmp  파티션된 정보보기
SELECT * FROM SYS.PARTITIONS where object_id = object_id('tbl_tmp')  
order by index_id  , partition_number 






 각 테이블이 어떤구조로 있는지 눈으로 확인 

select 'tbl' , * from sys.indexes where object_id = object_id('tbl') 
select 'tbl_tmp' , * from sys.indexes where object_id = object_id('tbl_tmp')




select * From sys.data_spaces where data_space_id = 65601 -- PRIMARY 에 속해있다.
select * From sys.data_spaces where data_space_id = 1 -- 파티션 그룹(PARTITION_SCHEME)에 속해있다


drop table tbl_tmp -- drop 하고 다시생성

스키마 참조하여 만들되,  이번엔 일부러 컬럼명만 다르게 해보았다.
 create table tbl_tmp (idx2 int , regdate2 datetime) on [PS_For_Date_FG5](regdate2)

> 다시 스위칭 시킨다. PARTITION_NUM 5 번에 있는거 4145개 데이터 SWITCH
> 각각의 원본의 PARTITION NUM 과 타깃(TBL_TMP) 파티션 번호를 틀리게 줘봤다

ALTER TABLE tbl SWITCH PARTITION 5 TO TBL_TMP PARTITION 5

| 오류 발생 컬럼명 다르다고 오류



스키마 참조하여 만들되,  이번에는 컬럼명도 같게 MSDN 시키는대로
drop table tbl_tmp
create table tbl_tmp (idx int , regdate datetime) on [PS_For_Date_FG5](regdate)
파티션 번호 다르게 해볼까?  오류 발생
ALTER TABLE tbl SWITCH PARTITION 5 TO TBL_TMP PARTITION 1
> 오류 : 그룹이 다르다고 오류를 뱉길래 조건이 다른 1/6번 그룹은 같은 FG1 얘는될까?

ALTER TABLE tbl SWITCH PARTITION 1 TO TBL_TMP PARTITION 6
> 오류 : 정의한 범위가 테이블 'partitionDB.dbo.TBL_TMP'의 파티션 6에서 정의한 범위에 포함되지 않습니다.
원하는대로 같은 파티션에 SWICH 처리 → [성공]
ALTER TABLE tbl SWITCH PARTITION 5 TO TBL_TMP PARTITION 5


확인 [FG5] 에 있는 데이터들이 모두 TBL_TMP 로 INSERT 되었다.
sp_partiton_view 'tbl'


테이블을 확인해보자
PARTITION_NUMBER 5 에 있던 데이터 1985개 그대로 TBL_TMP 에 들어가있다.
select count(*) From TBL_TMP
| 정확히 이야기하자면 TBL_TMP 테이블의 PARTITION_NUM 5 에 FG5 에 들어가있다.
| PARTITION_NUMBER 5 에 그대로 들어가있다.




SELECT * FROM SYS.PARTITIONS
Where object_id = object_id('tbl_tmp')  Order by index_id  , partition_number 



SELECT * FROM SYS.PARTITIONS 
Where object_id = object_id('tbl')  Order by index_id  , partition_number 



| index_id 가 왜  2개지?  나중에  인덱스에 대해서 포스팅할대 설명하기로하자 급하신분들은 구글링 하시길



PARTITION_NUMBER 5를  삭제하자(삭제는아니고 사실 Merge 이다)
sp_partiton_view 'tbl' -- 삭제 전확인


PARTITION_NUMBER 5를  삭제하자 (Merge)
 ALTER PARTITION FUNCTION PF_For_Date_FG5() MERGE RANGE ('2018-03-01 00:00:00.000')

sp_partiton_view 'tbl' -- 삭제 후 확인 (사실 삭제라기 보다 합쳐젔다)


아차! 테스트하다가 파티션 범위 밖의 데이터를 입력해보는것을 해보지 못하였다.

sp_partiton_view 'tbl'


파티셔닝 조건인 value 에 포함이 안되는 값(날짜) insert
 insert tbl values(10002 , '2018-12-01')  -- 5번 실행


sp_partiton_view 'tbl'



파티션 테이블 에서는 새로 알아야할 명령어 및 개념들이 몇가지 있다.

그리고 인덱스 상관관계 또한 이해해야 할 부분이 있다. 이는, 다음 포스팅때 오늘 실습해본 쿼리를 중심으로 알아보기로 
하겠다.



2018/01/31 16:37 2018/01/31 16:37
Posted
Filed under jQuery

ajax 에서 타 도메인(호스트 포함) 호출은 javascript(ajax)에서 SOP 정책위반(same origin policy) 이다.
즉, 같은 도메인 내에서만 호출이 가능하다. 하지만 개발 업무를 하다보면, 내부 또는 외부 API(REST 타입) 또는 페이지 정보 를 호출해야 하는 경우가 있다. 이를 위해서 서버를 허용 (CORS(Cross Origin Resource Sharing)  - Access-Control-Allow-Origin 헤더추가)하도록 설정(W3C 표준)하거나 다른 방법을 강구해야한다.

참고 : 아래는 SOP 정책 준수 와 위반 예제


 호출 URL : http://www.sooli.com/ajax_test/call_ajax.asp   아래 URL들을 호출 할 경우  ↓↓↓↓↓

* SOP 정책 준수
- http://www.sooli.com/data/sample.json   // 호출가능 :)
- http://www.sooli.com/XML/rss.xml  // 호출가능 :)
- http://www.sooli.com/API/REST.asp  // 호출가능 :)
- http://www.sooli.com/php/REST_PHP.php  // 호출가능 :)

* SOP 정책위반
- http://blog.sooli.com:81// 호출 오류 : 도메인은 같으나 포트가 다름  :(
- http://blog.sooli.com/ // 호출 오류 : 호스트가 다름 :(
- https://www.sooli.com/13  // 호출 오류 : 프로토콜이 다름 :(
- http://www.naver.com/mapApi/mapdraw.json  // 호출 오류 : 도메인이 다름 :(


※ 해별방법 : 크로스 도메인 호출 방법 

① 고전적인, iframe proxy
② CORS(Cross Origin Resource Sharing) 명시적 허용
③ 서버 사이드 단, 에서 I/O 방식
④ jQuery  ajax 옵션에서의  jsonp  콜백방식




① 고전적인, Iframe proxy
---------------------------------------------------------------------------------------------------------------------------------

* javascript 수준 + 서버파일 (JSON - ajax 를 이용하지 않음)
iframe proxy 방법의 경우, 개인적으로  예전에 많이 쓰던 방법이다-_-(사실 지금도 간혹쓴다.)

방법은 간단하다. 페이지에 보이지 않게, 히든 iframe 을 두고  그쪽 submit( or 페이지이동) 던져 , iframe 에서  저장 또는 iframe을 무언가를 로딩하면서, DB로 부터가져온 결과를 javascript  의 parent.객체ID 로 접근하여 화면에 반영 또는,  파일 I/O를 통해 읽어드린 내용을 파싱 또는하여 부모창에 반영하는 방법이다.




②. CORS(Cross Origin Resource Sharing) 명시적 허용
----------------------------------------------------------------------------------------------------------------------------------
* JSON - ajax 를 이용함
CORS 의 경우 W3C 의 표준안으로 모든 웹 프로그램 에서 지원한다. 

호출되는 페이지의 상단에 CORS 헤더를 추가하면 호출이 가능해진다. 일종의 타도메인에서 
자신을 호출하는 행위를 허락한다는 의미이다.

아래는 ASP 예시다.(PHP , JSP , .NET  각각 모두 지원함)

<%
    Response.AddHeader "Content-type", "text/xml"
    Response.AddHeader "Access-Control-Allow-Origin", "*"
%>
    ----- 이 부분에 필요 json 형식이든 text 형식이든 출력 한다. ------

<사용방법>
기존의 json 에서의 $.ajax 코딩시 똑같이 호출하면된다.

사내간의 크로스 도메인(호스토포함) 호출이라면, 쉽게 해결될수있는 문제일 수 있다.
(서버페이지의 위 2줄에 대한 코딩삽입에 대한 협업이 간단 할 수 있기때문이다.)
하지만, B2B , 또는 타회사 간의 호출되어지는, 외부 API 로 인경우 정책상 회의를 통해 
협업이 되어야하며, 그게 아닌 공개 API(데이터) 인 경우 CORS 설정이 안되어있을경우는 불가능하다.





③. 서버 사이드 파일 I/O 방식 
---------------------------------------------------------------------------------------------------------------------------------
* JSON - ajax 를 이용함
위의 CORS 가 안되는경우에 사용하는 방식이다. CORS가 허락되지않는 외부API 인경우 
서버 사이드 단 파일 I/O 통해 해결가능하다.

      "  여기서의 핵심은 SOP(same origin policy) 위반은 ajax 에서의 위반이므로, 그것을 피하고,
           서버에서 접근하여 Read & Write 하는  방식이다.   "

--- 생략 ---

// 클라이언트
$.ajax( {
        // url : "http://www.naver.com/api/mapPosition.json", → SOP 위반 호출불가 / 서버에서 호출                  url : "/API/CallRef.asp",  →  본인 Url 의 호출이기 때문에 호출가능
})

// 서버단 , /API/CallRef.asp
Set xmlHttp = Server.Createobject("MSXML2.ServerXMLHTTP")  
xmlHttp.Open "GET", "http://www.naver.com/api/mapPosition.json", False
xmlHttp.setRequestHeader "User-Agent", "asp httprequest"
xmlHttp.setRequestHeader "content-type", "application/x-www-form-urlencoded"
xmlHttp.Send
getHTML = xmlHttp.ResponseText
xmlHttp.abort()
set xmlHttp = Nothing
Response.Write(getHTML)  → 내용출력 ajax 가 읽어들임





④ jQuery  ajax 옵션에서의  dataType : "jsonp"  콜백방식
---------------------------------------------------------------------------------------------------------------------------------
ajax 에서는 SOP 정책을 피하기위해  JSONP(Json with Padding)의 콜백방식을 지원한다.
아마다 예전버전에는없었던거같은데, 사실 최근 jquery 를 공부하면서 알게된 방법이다.
백문이불여일견 아래 클라이언트 와 서버를 보자.
(사실, dataType : "jsonp" 방식은 기존의 json , text, html 등 타입방식과 완전 다른방법으로
접근한다. 나중에 기회가 되면 알아보기로하자 or 구글링 하면 다 나온다.)

<클라이언트 side>
$.ajax({

    type : 'GET',
    url : "http://blog.sooli.co.kr/ss.asp" ,
    contentType:"application/x-www-form-urlencoded;char-set:euc-kr",
    dataType : "jsonp",
    jsonpCallback:"callbackData", //  이 부분이 중요 , 
    success:function(data){ parsing(data); } // = success : parsing  같음
});

function parsing(data) {
       $.each(data, function(index, item)
       {
               alert(index);
               alert(item.name); 
               alert(item.tel); 
               alert(item.skill.item1); 
               alert(item.skill.item2);

               alert(item["name"]);           
               alert(item["tel"]); 
               alert(item["skill"]["item1"]); 
               alert(item.skill["item1"]); 
               alert(item["skill"].item2);
         }
      )

}


요즘 툴들이 좋아져서 인텔리센스 덕분에 오타날 확률이 적지만, 그래도 jsonpCallback 타이핑시
"C" 자가 대문자라는점 까먹지말자  jaonpcallback 하면 오류 난다.!!
그리고 jsonpCallback  의 value 인 "callbackData" 이부분도 서버에서 작성할때 대소문자가 같아야 한다.!!

jsonpCallback : 의 value 인 "callbackData" 이부분은 본인이 마음에 드는 아무값이나 작성해도된다

"callbcakData" , "sooliData" , "Data"  , "value123" 등 마음대로 단 서버사이드 wrapping 시 대소문자가 모두 같아야한다.


<서버 side>

위의 클라이언트에서 호출할대 jsonpCallback 에 적혀진 wrapping 용 값이 
서버사이드에서 데이터를 감싸줘야 호출히 오류가 안난다.
jsonpCallback:"callbackData"

즉 서버사이드에서는 json type 으로 값 출력시 
callbackData ( ~~~~~ 데이터 ~~~~ 이런식으로 
감싸줘야(wrapping)한다

아래소스  : http://blog.sooli.co.kr/ss.asp 
----------------------------------------------------------------

callbackData (   // callbackData 시작

[
    {

        "name": "sooli",
        "tel": "010-0000-0000",
        "skill": {
                    "item1": "server",
                    "item2": "mssql"
            }
    }

]

) // callbackData  끝


( 위 4가지 방법말고 다른 방법이 있으며, 알려주시면 좋겟습니다. - 공부하게요 ㄷ )

2018/01/24 14:43 2018/01/24 14:43
Posted
Filed under jQuery

- 당연한 이야기지만 대소문자는 반드시(속성) 구분해야한다.
- ajax 기본 인코딩 utf-8


* Ajax(json) 기본 형식


 $.ajax({


    url : "호출주소", // 자신의 도메인 파일 호출 할 것 (cross domain 기본지원 안함 - " cross-domain 호출하기 편 " 볼것)
    type : "GET" , // GET or POST
    async : true , // 기본 비동기(tr
ue) 동기로 할꺼면 false
    cache : true , // 기본 true (304) false(200)

    data: "데이터" , // 전송할 데이터
                     
       // $('폼아이디').serialize(); - 폼통째로 전달 시리얼라이징
                             // name=데이터&tel=데이터 - 쿼리스트링 방식
                             // data : {'name':'test'} , - json 타입( 바깥 따옴표없다. 안따옴표 필수)


    dataType : // 데이터 타입(응답결과시) xml , html , text , json , jsonp , script ,text
    timeout : 1000 , // 1초 - 서버응답대기시간 설정 (millisecond)

    contentType : // 응답되어 받을 문서의 Type 설정
   
                        (기본 : application/x-wwwform-urlencoded;charset=UTF-8)

    beforeSend : function() { } ,// 전송전 호출할 함수

    complete : function(jqXHR) { } , // 완료수 callback (complete or always)
    success : function(jqXHR) { } , // 성공 후 callback (success or done)
                                                        // jqXHR 안에 결과로온 데이터가 문자열로 들어있음
    error : function(jqXHR) { } , // 오류발생시 callback(error or fail )

 });





데이터 전송 1. data : "데이터" , - 전송할 데이터 array 와 object 로 json 화 하기
dataType : "JSON" 인경우 반드시 stringfy 해야한다.
---------------------------------------------------------------------------------------------------------------------------------------
var a = new Array();
var o = new Object();

o.name = "이름";
o.tel = "010-000-0000";

a.push(o);

var param = JSON.stringify(o); //
JSON.stringify 함수가 {"name" : "이름"} 로 만들어줌

data : param



데이터 전송 2. data : "데이터" - 폼 통째로 전송시 직렬화
----------------------------------------------------------------------------------------------
$('폼아이디').serialize();

data : $('#formID').serialize();



데이터 json 수신 . dateType : "json" 설정
----------------------------------------------------------------------------------------------

클라이언트 호출에 의해서 서버단 API 에서 json 타입으로 리턴 할 경우

* 서버 : JsonArray return;
----------------------------------------------------------------------------------------------
[
    {
   
    "name": "sooli",
        "tel": "010-0000-0000",
        "skill": {
                        "item1": "server",
                        "teim2": "mssql"
                    }
    },
    {
        "name": "pluginn",
        "tel": "010-1111-1111",
        "skill": {
                        "item1": "asp",
                        "item2": "asp.net"
                    }
    }
]
* 클라이언트
----------------------------------------------------------------------------------------------


success : parsing // 참조함수 - delegate 같은느낌


success : function(data){parsing(data);} // 일반함수


function parsing(data)
{
   
    $.each(data, function(index, item)
    {
       

        alert(index);
        alert(item.name);
        alert(item.tel);
        alert(item.skill.item1);
        alert(item.skill.item2)
       
        alert(item["name"]);
        alert(item["tel"]);
        alert(item["skill"]["item1"]);
        alert(item.skill["item1"]);
        alert(item["skill"].item2);
    })
}




* AjaxSetup(json) 같은 페이지에서 ajax를 여러번 쓸경우 셋팅


$.ajaxSetup({

    url : "http://.....",
    type : "POST",
    async : true,
    timeout : 1000,
    error : function() { alert("error");}

});


$.ajax({ // ajaxSetup 상속됨

    success : function(){
   
    // 처리 #1
    }

});


$.ajax({ // ajaxSetup 상속됨

    data : "{}",
    success : function()
    {
   
    // 처리#2
    }

});





* A
jax 각각의 type 방식 호출


$.get( URL , "콜백함수(성공시)" , "데이터타입");
$.post( URL , "콜백함수(성공시)" , "데이터타입");


$.get().done().fail().always(); // 메소드 릴레이 호출가능

done(function(jqXHR){}) , // (done is success)
fail(function(
jqXHR){}) , // (fail is error )
always(function(jqXHR){}) // ( always is always)







* Ajax 이슈


IE 에서 $.ajax 로 같은 Url 호출시 변경되지않은 결과값이 나옴

방법 1 : url : "http://..... ?타임스탬프활용" , // 타임스탬프 및 랜덤 수 를 이용하여 Url fake 줌
방법 2 : 호출 type 을 "POST" 변경 그런데 이 방법의경우 IE 에서는 Cache를 계속 사용하기도 함)
방법 3 : cache : false



* 캐쉬사용안함 설정의 의미,
웹에서의 모든 설정이 마찬가지지만 , cache 설정없음은 304 응답코드 없음을 의미한다.
클라이언트 → 서버요청시 요청한 페이지의 리소스를 캐쉬에서 활용하지 못하고 서버로 부터 모두
다시 받음으로서 속도에 영향을 미칠 수 있다. (단순,text type 이라면, 괜찮을듯 싶다.)

 

2018/01/23 16:49 2018/01/23 16:49
Posted
Filed under jQuery

jquery 첨에 나왔을때.. jquery 를 이용안했던 가장큰이유는 
첫번째 익숙한 레어코딩, 
두번째가. 바로 이 로딩 시점문제였다 ,
하지만 세번째 더 큰 문제는.. 공부를 안해서...첫번째,두번재 오해(?) 가 생겼다.

jquery 의 방식은 ready  펑션이 onload(window) 방식에서라는 착각에서이다, 
$(document).ready 의 로드 시점은 window.load 이 시점과 다르다,

$(document).ready vs $(window).load  
로딩시점

$(document).ready(handler) 의 로드 시점은 페이지가 로딩시 필요한 최소한의 DOM Tree를
생성한 직후 실행된다. 이는 페이지 구성에 필요한 이미지 , text , 미디어  , css 등과 관계없이
DOM tree 구성 후 실행되에 ready 안에 코딩들은 인터프린터 방식으로 컴파일한다.

$(window).load(
handler) 의 로드 시점은 DOM tree 로딩후 페이지에 필요한 text ,image , media ,
font , css 등 모든 요소들을 로딩 한후 일어난다.

아래를 보고 로딩 이벤트에대해 다시한번 숙지하자



$(document).ready(function(){  }); 
 

=  $(function(){});  와 같음
$(document).read(function(){  // 변수선언 //jquery 코딩 // 바인딩 // 함수생성 // 레어js 코딩가능});  
- DOM Tree 로딩 후 바로 호출
- 변수 , 함수의 경우  지역변수/ 지역함수 (stack) , 안에서만 사용가능


$(window).load(function(){}); 
$(window).load(function(){  // 변수선언 //jquery 코딩 // 바인딩 // 함수생성 // 레어js 코딩가능});  
- DOM Tree + 페이지 객체들 로딩 후 호출
- 변수 , 함수의 경우  지역변수/ 지역함수 (stack) , 안에서만 사용가능


<script language="javascript">

     $(document).read(function() { 
alert("document ready");  });

      $(window).load(function() {  alert("window call"); });

      alert("global call")

</script>

결론 - 로딩순서 

1.global call 
2.document ready
3.window call.



2018/01/19 11:52 2018/01/19 11:52
Posted
Filed under MSSQL

SYNONYM 설정시 현재 (2016) 까지는
데이터베이스.스키마.개체명 까지 다 넣어야,,, 
동의어로 지정할수있다
(테이블명 까지 지정해줘야함 )

TestDb  데이터베이스에  TestSchema  에 TestTable   // FQN 접근시
→ select * from  TestDb.
TestSchema.TestTable   

create SYNONYM 동의어명 For   데이터베이서.스키마.테이블명

Create SYNONYM  SN_Test For TestDb.TestSchema.TestTable 
→ select * from SN_Test 


* 기술적으로 복잡함이 없어 FAQ로 구성해 보았다.
-------------------------------------------------------------------------------------------------------------------------
Q) 시놈님 생성은?
(위에) create SYNONYM 동의어명 For   데이터베이서.스키마.테이블명

Q) 시놈님 생성시 dB명만 해도 되나요?
Create SYNONYM  SN_Test For TestDb   만들어짐!! 오케이 된다!
 select * from SN_Test.스키마명.테이블명   -> 오류!! 안됨!!

만들어는 지나, 접근이 안됨,,
결론은 안됨!!!!!

Q) 그럼 dB명.스키마 까지... 해도 되나요?
 이거? Create SYNONYM  SN_Test For TestDb .TestSchema 
 select * from SN_Test.테이블명 오류!! 안됨!!

만들어는 지나 접근이 안됨
결론은 안됨!!!!!

Q) 시놈님 삭제는 ?   
drop SYNONYM 동의어명;

Q) 시놈님 수정은?
수정은없음 drop & Create

Q) 시놈님과 연동 동의어의 개체가 사라지면? 
    따로 drop 해줘야함  - 관리필요 (drop SYNONYM 동의어명)

Q) 테이블 새로 만들어지면 시놈님 자동생성안되나요 ? 
안됨,  따로 create 해줘야함  - 관리필요


Q) create 시놈님 안에 연결 개체를 바꿀려면(수정)?  
drop 하고 create 하삼 alter 없음

Q) 테이블 100개면 시놈님 연결하러면요?
create SYNONYM 100번해야함 해야함

Q) 프로시져도되요?  
  프로시져는 개체 , 당연됨 함수도됨 그냥 똑같음
 
 Create SYNONYM 동의어명 For sp_memberUtil
    -> exec 
동의어명

Q) 프로시저 시놈님만들었는데? 파라미터는 어떻게해야되나요?
   

   -> exec 동의어명  'C' , 'UserID'     -- 기존 프로시져와 똑같이 하면됨 
   -> 기존 프로지서 exec sp_memberUtil  'C' , 'UserID'
  
Q) 테이블 2000개 프로시져 1만개... 모두 만들려고합니다...
     쉽게 만들수있는방법은 ?  

    -- 참고 ---------------------------------
    select * from sys.tables
    select * from sys.synonyms

    아래와같이 동적으로 생성이 가능하다. :)
    
 

     declare @var nvarchar(100)
     set @var = 'create synonym '  + 시놈님명 +  ' for ' + 객체명
     EXEC SP_EXECUTESQL @var  --    EXEC(@var) 로 해도됨

     또는, 변수로 처리

     
declare @var nvarchar(1000)
     declare @tbl  nvarchar(20)
     declare @syName  nvarchar(20)

     set @syName = 'sy_t'
     set @tbl  = 'partitionDb.dbo.tbl'

     set @var = 'create synonym ' + @syName + ' for ' + @tbl

     EXEC SP_EXECUTESQL  -- 또는,    EXEC (@var)

     단, 아래와 같이 sp_executesql 생성시 파라미터로 전달은 안된다.

     set @syName = 'sy_t'
     set @tbl  = 'tbl'

     -- 파라미터로 객체명 전달시 오류 발생
     set @var = 'create synonym  @syName   for  @tbl'
     EXEC SP_EXECUTESQL @var , N'@syName  varchar(20) , @tbl  varchar(20)' , @syName , @tbl

 


Q) 전 마우스로 밖에못하는데 어디서 만들어요?
   당황하지말고 SSMS 에 DB [+] 클릭  Table 있고  View 있고 그아래쯤 SYNONYM 
   거기서 우클릭해서 해보길.



------- 2018-01-29 추가 ----------------------------------------------------------------------------------------------------
Q) 시놈님과 연결한 [A] 테이블을 drop  후 같은이름으로 테이블[A] 다시 만들었는데  어떻게 되나요?
시놈님도 다시 만들어야하나요?

결론 부터 말하면 기존에 [A] 테이블과의 연동이 끊기고 새로만든 [A] 테이블과 자동연동된다.
이는 시놈님 구조가 테이블의 object_id 가 아닌 테이블명과 연결되기때문,

-- 시놈님의 시스템 테이블
 select * from  sys.synonyms  -- base_object_name 이 실제 연동된 테이블

① 위의  sys.synonyms  테이블을 select 해보시면  base_object_name 에 연결된 테이블 명칭이있습니다.
② 시놈님의 동의어 만들때 개체의 object_id를 이용하지 않습니다. (이름(테이블명) 사용함)
③ 결론은 다시 만들어진 테이블 A 와 시놈님의 자동으로 연동 됩니다.(이유는 ②번과 같습니다.)

* 시나리오
1년전 특정 로깅을 위해 Table_X 테이블을 만들었고  Table_X 동의어로 synonym  "SY_X"를 설정하여,,,
프로시저 및 접근시 SY_X 로 모두처리하였습니다. 5년후 많이 쓰지않는 테이블 이고, 정책에 반하는 테이블이라, drop 시키고, 새로운 기획에 의해 Table_X 를 다시 만듬 SY_X  는 그대로 유효한가?



위에서 이야기한대로 object id 가 아닌 테이블명 으로 연동되어 그대로 이용가능하나, 새로만든 테이블의
구조가 기존과 다르다면, SY_X로 박혀있는 프로시져 기타 소스들은확인 & 수정 할 필요가 있다.





 
  
 
 
    
  





2018/01/18 15:52 2018/01/18 15:52