c# MS SQL SqlBulkCopy 사용법- MSSQL 대용량 데이터 입력하기

수만~수십만 행의 데이터를 insert하는 C# 프로그램을 개발한다고 가정해 보죠. 

트랜잭션을 걸고 for문 돌면서 insert 쿼리 날리면 어마무시한 시간이 걸립니다. 최근 테스트한 바로는 내부 네트워크로 연결된 MS-SQL에 3만줄의 데이터를 입력하는데 3분정도가 걸렸던 것 같습니다.  너무 느립니다. 앞으로 5만줄, 10만줄이 될 수도 있는데 어쩌나 하며 구글링...

그리고 SqlBulkCopy라는 놈을 발견합니다. 이름에서 보듯 벌크로 데이터를 인서트할 수 있는가 봅니다...이놈은 MS-SQL전용이라 OleDb를 지원하지 않습니다. OleDb에서 트랜잭션을 열고 SqlBulkInsert를 OleDb 트랜잭션 하위에 둘수는 없습니다. 벌크인서트 자체가 MSSQL에만 적용가능하니 그런듯..



아무튼 사용법은 아래와 같습니다.

1. SqlCommand 를 열고 트랜잭션 생성

2. 벌크인서트 전에 다른 여러 SQL구문 처리 

3. 인서트할 테이블 구조와 동알한 DataTable 생성 및 데이터 입력

4. SqlBulkCopy.WriteToServer()함수 수행 후 close()


간단하죠? ㅎㅎ

3분걸리던 입력시간이... 3초로 줄었습니다.+_+ (네트웍환경이 안좋은 원격지라면 시간이 좀 더 걸리겠죠?)





Trackbacks 0 / Comments 0

Leave Comments

c# if DEBUG 와 Conditional("DEBUG")의 차이점

두 구문 모두 컴파일 모드에 따라 실행여부를 결정짓게 하기 위해 사용합니다.

하지만 작동방식에서 차이가 있는데요. #if DEBUG ~ #endif 에  감쌓인 영역은 릴리즈로 컴파일 할 경우 IL(Intermediate Languag)에 도달하지 않지만 Conditional("DEBUG")의 경우는 IL까지 만들어지지만 해당 함수가 호출되는 곳이 컴파일 될때 호출자체가 생략되는 구조입니다.

그렇다면 언제 어떤놈을 사용해야할까요


#if 문 쓰는 전형적인 경우입니다. 긴 설명이 필요없죠? DEBUG모드인지 여부에 따라 두 구문중에 하나의 구문만 유효하게 됩니다.

#if DEBUG
        public const String ENDPOINT = "Localhost";
#else
        public const String ENDPOINT = "BasicHttpBinding";
#endif


하지만 이런경우는 어떨까요

#if DEBUG
    public void DoSomething() { }
#endif

    public void Foo()
    {
#if DEBUG
        DoSomething(); //This works, but looks FUGLY
#endif
    }

뭔가 좀 복잡? 지저분합니다.. 게다가 DEBUG모드에서만 실행되어야 하는 DoSomething()함수를 여러군데서 호출하고 있다면 호출하는 곳곳마다  #if DEBUG~ #endif로 감싸놓아야 합니다. 성가신 작업이기도 하고 지저분하기도 합니다.


하지만 아래처럼 Conditinal Atturibute를 사용하면 코드가 한결 깔끔해 지지요.

[Conditional("DEBUG")]
public void DoSomething() { }

public void Foo()
{
    DoSomething(); //Code compiles and is cleaner, DoSomething always
                   //exists, however this is only called during DEBUG.
}

Conditional 속성을 가진 DoSomething() 함수는 중간언어까지 번역은 되지만 실제 Foo()가 DEBUG 컴파일 될 때에만 유효하게 되며 DEBUG가 아닐 경우는 함수 호출 자체가 생략됩니다.


개인적으론.. Conditional을 남발하면 나중에 디버깅할 때 불편할 수도 있겠다 싶네요.. 함수선언을 항상 봐야하니까요.. 너무 남발하는 것도 안좋을 듯.




Trackbacks 0 / Comments 0

Leave Comments

c# string Split 응용 - KeyValuePair<>를 통해 인덱스 추가하기

오랜만에 개발프로젝트를 맡아 직접 개발까지 하고 있습니다.  10여년 이상을 네이티브 C++와 MFC 하고만 놀다보니 4세대니 5세대니 하는 개발언어보다 C++가 친근했었는데요.  최근에 들어서는 점점 생각이 바뀌어 가고 있네요.. 한참 쌓아올린 c++ 관련 개발 리소스가 아깝긴 하지만 개발 생산성 측면에선 c#을 따라갈 수 없다는 걸 인정합니다. 

개발하다보니 c++와 다른 대입참조 때문에 혼란을 겪기도 하고 이래저래 좌충우돌 하고 있지만 참으로 오랜만에 개발하는 재미를 느끼는 중입니다. 

넋두리는 이쯤에서 그만하고..

----------------------------------------------------------------------------------

복잡해 보이는 LINQ, 람다식 사용법을 공부하면 개발 생산성에 큰 기여가 될 듯합니다. 다만 코드 유지보수의 측면에서는 다소 불리한 면도 없지 않을것 같습니다. 주변에 몇몇 개발자들은 LINQ, 람다식 전~혀 안쓰고 있더군요. 아니 사실 관심도 별로 없어보입니다. 


아래 코드는 LINQ와 간단 람다식을 이용하여 int, string 쌍을 가지는 리스트에 콤마 구분자로 된 string배열 객체에 int형 인덱스를 부여하여 add하는 코드입니다.  간단한 몇 문장으로 복잡한 형태의 자료구조의 입출력을 구현했습니다. 이 코드를 네이티브 코드로 구현하려면 아마 훨씬 복잡해 졌겠지요? 

 


 

c# 멋집니다. ㅋ


콘솔에 찍힌 결과 값입니다. 예상대로로 군요..



Trackbacks 0 / Comments 0

Leave Comments

c# if 문 or 연산 중복 제거하기

최근 c# winform개발을 주로 하고 있는데요.. 네이티브 c++만 하던 저로써는 .NET환경이 신기하기도 하고 놀라워서 공부해 가면서 개발하는 맛이 쏠쏠합니다.

c# 3.0부터 확장메소드라는 놈을 지원하는데 이놈이 개발 편의성을 올려주는데 정말 큰 몫을 하는것 같습니다.

아래와 같은 형태의 조건문을 짜다보니 계속 반복되는 인스턴스가 눈에 거슬립니다.

한 변수에 대해 여러 or연산을 해야하니 nData가 많이 중복될 수 밖에 없죠..

이때 c# 확장메소드를 활용하는 팁이 있습니다.

위와 같이 확장메소드를 이용하면 처음의 코드가 아래처럼 변합니다.

어떤가요? 중복되는 정보가 제거되어 훨씬 깔끔해진 모습이죠? 만약 비교해야하는 내용이 2,3개가 아니라 불가피하게 아주 많아지게 되면 이런 확장메소드의 활용이 좀더 빛을 발하지 않을까 생각됩니다. 







Trackbacks 0 / Comments 0

Leave Comments

64bit 컴퓨터에서 32bit 오라클 OLEDB 드라이버 로드하기

64bit PC의 경우 UDL파일을 로드하면 64비트용 드라이버만 보여집니다.

 

아래와 같이 직접 32비트용 oledb 드라이버를 실행해 줘야 합니다.

 

C:\Windows\syswow64\rundll32.exe "C:\Program Files (x86)\Common Files\System\Ole DB\oledb32.dll",OpenDSLFile test.udl

 

귀찮으니 그냥 배치파일로 만들어놓고 사용하기로~

 

 

UDL_RUN.bat

 

@echo off
C:\Windows\syswow64\rundll32.exe "C:\Program Files (x86)\Common Files\System\Ole DB\oledb32.dll",OpenDSLFile test.udl
exit

 

 

첨부파일 두개를 같은 위치에 놓고 UDL_RUN.bat파일을 실행하면 32비트용 드라이버를 확인할 수 있습니다.~

 

test.udl

UDL_RUN(32).bat

 

Trackbacks 0 / Comments 0

Leave Comments

c# listview item 사라짐(disappear) 현상 해결방법

 

 

 

 

 

 

 

 

 

 

 

 

아래 코드에 어떤 문제가 있을까요.

 

private System.Windows.Forms.ListView lvData;

 

private void ReceiveItems(object sender, PublisherEventArgs e)
        {
            Invoke(new MethodInvoker(delegate()
                {
                    try
                    {
                        WriteLog("[" + DateTime.Now.ToString() + "] " + e.eventData);

                        List<StockData> collection = new List<StockData>();

                        lvData.BeginUpdate();
                        ListViewItem item;

                        foreach (string s in sTokens)
                        {

// do something..

                        }
                        lvData.EndUpdate();
                    }
                    catch(Exception ex)
                    {
                        WriteLog( ex.Message.ToString());
                    }
                }));
        } 

 

       

listview가 update될때 beginUpdate()를 호출하고 endUpdate()를 호출 전까지 화면그리기를 중단하도록 합니다. 이유는 컨트롤에 데이터 업뎃이 한번에 깔끔하게 되기위해서 이런 구조를 쓰는데요..

 

exception발생시 EndUpdate()를 호출하지 못하는 상황이 발생합니다.

 

한번 이렇게 꼬여버리면 다음번에 정상적으로 해당 함수들이 호출된다 하더라도 listview는 더이상 정상적으로 작동하지 않게 됩니다. -화면상에 보이지 않게 되는거죠.-

 

그럼 어떻게 해야할까요?

 

 

네.. 아래와 같이 finally구문을 사용하는게 일반적인 방법이 되겠습니다.

 

 

private System.Windows.Forms.ListView lvData;

 

private void ReceiveItems(object sender, PublisherEventArgs e)
        {
            Invoke(new MethodInvoker(delegate()
                {
                    try
                    {
                        WriteLog("[" + DateTime.Now.ToString() + "] " + e.eventData);

                        List<StockData> collection = new List<StockData>();

                        lvData.BeginUpdate();
                        ListViewItem item;

                        foreach (string s in sTokens)
                        {

// do something..

                        }
                         // lvData.EndUpdate();
                    }
                    catch(Exception ex)
                    {
                        WriteLog( ex.Message.ToString());
                    }

                    finally

                    {

                        lvData.EndUpdate();

                    }
                }));
        } 

 

 

 

 

try ~ catch구조에서 꼭 실행되어야만 하는 구문은 finally에 넣는 것 정도의 코딩습관을 들이는게 바람직하지 않을까요?

 

Trackbacks 0 / Comments 0

Leave Comments

MS-SQL Linked server( DB-LINK) 설정

다음번 검색질을 줄이기 위해...

 

 

 

 

 

sp_addlinkedserver
'DB2',
'MSSQL',
'SQLOLEDB',
'127.0.0.1',
NULL


sp_addlinkedsrvlogin
'DB2',
'false',
NULL,
'sa',
's9ak2!'


sp_testlinkedserver
DB2

 

select * from DB1.TESTDB.dbo.VW_PA01

select * from DB2.TESTDB.dbo.VW_PA01

 

Trackbacks 1 / Comments 0

Leave Comments

VS2010 에서 Dialog 클래스 생성후 가상함수 재정의시

기존 (VS6.0)프로젝트를 VS2010에 가져와 개발할 경우

새로운 다이얼로그 클래스 생성시 CDialog 를 상속받게 하고

자동으로 클래서 생성하면 아래외 같은 클래스를 헤더파일에 자동으로 인클루드한다.

 #include <afxcontrolbars.h>

 

이게 있으면 클래스마법사로 가상함수 재정의 오류가 난다.

afxcontrolbar.h 인클루드 제거하면 정상작동함.

 

Trackbacks 0 / Comments 0

Leave Comments

Windows7에서 Graphspy

http://msdn.microsoft.com/en-us/library/windows/desktop/dd390650(v=vs.85).aspx

 

Windows 7에서는 AddToRot를 해도 GraphEdit에서 나타나지 않음.

 


"Starting in Windows Vista, you must register proppage.dll to enable this feature. Proppage.dll is included in the Windows SDK."

Graphedt.exe 경로에 있는 proppage.dll 를 서버 등록하면 작동.

regsvr32 proppage.dll

x86이냐 x64냐에 따라 해당 graphedt를 잘 선택해야함.
 

 

 

Trackbacks 0 / Comments 0

Leave Comments

libvlc 기반 wrapping class VLCWrapper 동영상 재생문제

VLC관련 자료들을 들여다보다 Alex Skoruppa 가 만든 libvlcwrapper class 발견.

가져다 test 해본결과 대만족!! 그런데 일부 파일이 열리지가 않는다..

open부터 따라가봤더니 큰 문제가 없어보였는데..

media path 를 넘겨주면 pointer도 잘 넘겨주고.. 그런데 동작을 안한다.

아니 어떤건 되고 어떤건 안된다.. plugin이 잘못되었나 확인해봤는데 문제가 없다.

다시 천천히 살펴본 결과 파일명에 한글이 들어가 있으면 playback이 안되었다.

googling 결과 utf8로 넘겨서 해결한 사례 발견  :   http://en.usenet.digipedia.org/thread/17096/5693/

역시 charactor encoding 문제였네..

근데 왜 포인터핸들은 잘 넘겨주는걸까..

아무튼 아래와 같이 해결..

원 클래스가 CPOL 라이센스라서 아무것도 안해도 되네..원저자에게 알려는 줘야겠다.

VLCWrapper is distributed under the Code Project Open License (CPOL).

 

// in VLCWrapper_src_vlc_2_0_0\VLCWrapperImpl.cpp

void VLCWrapperImpl::OpenMedia(const char* pMediaPathName)
{
    // Load a new item
    // convert utf8 by likehood
    std::string c(pMediaPathName);
    if(!is_utf8(pMediaPathName))
    {
      std::string s(pMediaPathName);
      c = convMbcs2Utf8(s);
    }
    pMedia_ = libvlc_media_new_path(pVLCInstance_, c.c_str());
    libvlc_media_player_set_media (pMediaPlayer_, pMedia_);   
}

The Code Project Open License (CPOL)

* 저작권 보호: 예
* 상용 소프트웨어에서 사용 가능: 예
* 버그 패치 및 기능 확장 제공의 의무: 아니오
* 명시적 특허권 행사 가능 여부: 예
* 사유 프로그램 (소스 비공개 프로그램)에서 사용 가능 여부: 예
* 라이센스 전파 여부: 아니오

Trackbacks 5 / Comments 0

Leave Comments