출처 : http://guslabview.tistory.com/195


MySQL로 작업할때, Where절을 이용하여 Update 혹은 Delete를 하는 경우 1175 에러를 발생하면서 사용자가 실행한 쿼리문이 실행이 되지 않는 경우가 있습니다.


Error Code: 1175

You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column


1175 에러의 경우 Safe Update가 적용이 되어 있어 Where 절을 사용해서 Update를 못하게 설정상 막아 놓은 것입니다. 따라서 이설정 값만 변경해 주면 되겠죠. 1175를 해결할 수 있는 방법은 아래와 같이 2가지 방법이 있습니다.


1) SQL 구문 이용하여 설정 변경


쿼리 구문에서 SET SQL_SAFE_UPDATES = 0 으로 하여 설정을 변경할 수 있습니다. 아래와 그림과 같이 걍 실행만 하시면 됩니다. 



2) 옵션 창을 이용하여 설정 변경


Edit - Preference를 이용하여 옵션 창에서 변경할 수도 있습니다. 먼저 Preference 창을 엽니다.



"Safe Updates" 블라블라 되어있는 부분에 체크되어 있는 부분을 해제하시고, MySQL에 다시 접속을 하시면 해결할 수 있습니다.



2번째 방법보다는 1번째 방법이 효율적입니다. 한방에 되니깐요!! 재접속도 필요가 없습니다.

그럼 이만 줄이겠습니다.


출처:http://gnujava.com/board/article_view.jsp?article_no=1666&menu_cd=29&board_no=16&table_cd=EPAR06&table_no=06


Mysql DB 데이터 전부를 다른 서버로 옮기는 작업중...

 

방법은 콘솔에서 백업파일 생성 및 복원하는 법과

Workbench 에서 백업파일 생성 및 복원하는 법이 있다.

 

마우스로 까딱만 하면 되는 Workbench에서 하는게 편하나

나는 콘솔로 백업파일 생성 및 복원을 하였다.

 

 

DB전체백업 : mysqldump -u [DB계정] -p [DB명] > [파일명].sql

특정 테이블 백업 :  mysqldump -u [DB계정] -p [DB명] [테이블명] > [파일명].sql


mysql\bin> mysqldump -u root -p [DB명] > C:\dump130507.sql

 

파일을 생성할 장소를 지정할 수도 있습니다.

지정안하시고 파일명만 하시면 mysql bin 폴더에 들어가 있을 겁니다.

 

이제 그 파일가지고 이전할 서버로 가져와서

 

DB전체복원 : mysql -u [DB계정] -p [DB명] < [파일명].sql

 

mysql\bin > mysql -u root -p [DB명] < C:\dump130507.sql

 

하고 DB 확인하면 테이블들과 데이터가 모두 똑같이 이전된 것을 확인 할 수 있습니다.

여기 까지 콘솔로 하는 법이었습니다.

근데 해본결과 콘솔이 더 편하네요;;

 

 

*번외편 (Workbench로 백업/복원하기)

 

Workbench를 실행시킵니다.

 

Server Administration에 DB 서버 매니저에 들어갑니다.

 



암호를 치고 들어가면 DB 서버를 매니져하는 창이 뜨게 됩니다.

여기서 아래

DATA EXPORT / RESTORE 에

Data Export (데이터 백업)

Data Import/Restore (데이터 복원)

 



Data Export 들어가셔서

 

옵션이 두가지가 있습니다.

위에 라디오박스를 체크하면 테이블별로 파일을 생성해줍니다.

아래 라디오박스를 체크하면 파일 하나에 전체 테이블이 들어가도록 생성합니다.

저는 전체 DB를 백업할 것임으로 아래 옵션을 선택하고

Start Export 버튼을 클릭!

해당 디렉토리에 sql 파일이 생성된것을 확인 할 수 있습니다.




Data Import/Restore 에 들어가셔서 복원을 하시면 되는데

여기도 같은 옵션이 두개가 존재합니다.

백업파일이 존재하는 폴더를 가져오는것과

백업파일을 가져오는 옵션 이렇게

저는 전체 백업파일을 생성했으므로 아래 파일을 가져오는 옵션을 선택하겠습니다.

(그림은 폴더를 가져오는걸로 선택하게 찍었네여;;;;;;;)

Start Import 하면 끝~
 

 

 

저는 workbench에서 뭔가 옵션이 막혀있는지 안되가지고

콘솔에서 때렸네여..

 

아 데이터베이스를 Default로 Set 해주셔야 아마 들어갈 겁니다!

해당 DB에 마우스 우 클릭 -  set as Default Schema


그럼 이만!


복원중에 단일 사용자 모드가 뜨는 경우가 있는데


이또한 원인은 잘 모르겠습니다.


해결 방법은


alter database [DB 명] set multi_user;




MSSQL을 사용 도중 복원을 하게 되면 자주 이런 현상이 나타났습니다.


원인은 아직 파악을 못했고 검색 결과 해결 방법을 찾았다.


- RESTORE 명령으로 복원 후 사용자 데이터베이스 '복원 중' 상태 -


해결방법은


RESTORE DATABASE DB명 WITH RECOVERY



출처 : http://blog.naver.com/kikky22/140040666763


ORCLE이 정말 좋은 RDB라는 것을 알게 하는 것이 바로 페이징 기법일거라 생각되네요.

MySQL도 내부적으로 페이징이 가능한 쿼리를 지원해주지만 MSSQL은 최근 2005버전까지도... 좋은 페이징 기법을 소개하지 못하고 있는 것 같네요. 성능 좋은 페이징 기법이 공개된 것이 있기도 하지만... 초심자에게 쉽지 않은 쿼리들인 것 같습니다.

 

이에 조금 쉽게... 어떻게 하면 성능이 향상되는지를 설명해 보려고 합니다.

 

아래의 내용은 온라인상에서 바로 작성하는 내용이고 맞춤법등이 틀릴 수 있기 때문에 copy해서 사용하지 마시기 바랍니다.

개념을 잡는 정도로 활용하시면 좋을 것 같습니다.

 

 

MS SQL의 페이징 기법의 키는 TOP 키워드입니다.

 

#1. TOP과  클러스터드 인덱스

SELECT TOP 10 ID, subject, contents FROM TBL

이 쿼리는 누구나 알고 있는 쿼리입니다. 여기서 중요한 것이 TOP 10 입니다.  상위 10개만 갖고 오겠다는 뜻입니다.

MSSQL은 내용저장을 클러스터드 인덱스 순으로 저장을 하게 됩니다. 만약 ID를 PK로 지정하셨거나 따로 클러스터드 인덱스로써 ID를 지정해 놓으셨다면 ID순으로 자동으로 정렬이 되어 상위 10개만 가져오게 됩니다.

 

기본키는 반드시 설정할 필요는 없습니다. 다만 레코드를 구분하는 아이디값을 대게의 경우 기본키로 놓게 되는데요.

사실 기본키가 성능에 있어서의 의미는 없다고 봅니다.(확인된 바 없음)

기본키는 자동으로 인덱스 컬럼이 된다는게 의미가 있겠죠. 그것도 테이블당 딱 하나 사용할 수 있는 클러스터드 인덱스로 자동 설정됩니다. 헌데 문제는 ASC로 설정된다는 것입니다.

웹페이지에서 최근 글의 경우는 대부분 DESC로 정렬합니다. 즉 최근 글을 먼저 표시해주지요. PK로 만들더라도 꼭 ID를 DESC로 인덱스하도록 만들어야 합니다.

바로 이 유일 인덱스 컬럼이 성능을 좌우하는 핵입니다.

초심자의 경우 인덱스의 중요성을 넘기는 경우가 많은데요. PK가 중요한 것이 아니라 정렬을 원하는 컬럼을 클러스터드 인덱스로 만들어 놓는 것이 성능에 가장 중요합니다.(레코드 수가 늘 수록 엄청난 성능 향상이 있습니다.)

팁) TOP 10 PERCENT라는 키워드도 가능합니다. 말 그대로 전체의 10%만 가져온다는 것입니다. 쓸모가 많은 팁이라 생각되네요.

 

#2. 가장 많이 쓰이는 페이징 쿼리

SELECT TOP 10 ID, subject, contents FROM TBL where ID not in (SELECT TOP 현재페이진 이전까지의 모든 게시물 수 ID FROM TBL order by ID DESC) order by DESC

참 좋은 쿼리입니다. MS SQL에서 나올 수 있는 가장 간결하고 좋은 쿼리가 아닌가 싶습니다.

저역시 작은 규모의 게시판 종류는 무조건 이 쿼리를 이용합니다. 유지보수가 편하기 때문입니다. 누구나 쉽게 알아 볼 수 있기 때문에 제가 도저히 못 봐줄 유지보수 프로젝트라면 다른 사람이 대신할 수 있는 쿼리이기 때문에... 이 쿼리를 즐겨사용합니다.

다만 이 쿼리에는 조건이 하나 붙습니다.

 

사용자들이 100페이징 이하(게시물 수로 2000개 이하정도)의 글을 되도록 조회한다.

 

이 쿼리는 2만건 이하의 테이블에 적당하다고 생각됩니다.

1페이지라고 하면 성능이 최고가 되며

2페이지라면 not in 안의 쿼리문에 의해 한페이지가 10개의 글이라고 가정하면 10개를 일단 불러 들이게 됩니다. 제거를 위해서죠.

3페이지라면 20개를 불러들여서 제거를 해야 하겠고

4페이지라면 30개를...

그럼 100페이지라면 990개의 글을 읽어 들여야 겠군요. 990개를 먼저 불러 들이는 것이 문제입니다.

 

가장 심플한 쿼리이지만 DB에 어느정도의 부하를 주는 쿼리라는 것을 알 수 있습니다.

개인적으로 레코드셋종류의 객체에 내용을 불러오는 쿼리는 0.1초 이전에 끝나야 한다고 생각됩니다. 물론 검색이 들어가면 이야기가 달라지지만 기본적인 형태(아무런 검색이 없는 경우)에서는 0.1초 이하에서 OPEN을 끝내는 것이 좋다고 생각되네요.

 

#3. ORDER BY문

아시다시피 ORDER BY문은 정렬의 조건입니다. 위 쿼리의 경우 ORDER BY ID DESC이니깐 ID에 대해 내림차순으로 정렬하겠네요. 사실 ORDER BY 문은 안써주는 것이 성능에 가장 좋습니다.

만약 ID를 클러스터드 인덱스로 지정해 놨다면 안써도 될 것 같습니다. 클러스터드 인덱스를 내림차순으로 지정해 놨다면 ORDER BY ID DESC는 성능에 전혀 영향을 미치지 않습니다. 가끔 MSSQL에서 서브쿼리를 썼을 경우 원하는 값을 리턴하지 않습니다. 이유는 모르겠습니다. 서브쿼리문을 가져오는 방법에서 더 빨리 가져오려고 하는 그 부분에서 나오는 문제일거라 생각되네요.

클러스터드 인덱스로 지정했을 경우 ORDER BY ID DESC는 되도록이면 넣으시는게 좋습니다. 정확성을 위해서!;

 

#4. 성능저하 요소 SELECT COUNT(*) FROM TBL

NOT IN 쿼리보다 심플한 페이징 쿼리는 MSSQL에서 없는 것 같습니다. 개발자 입장에서 프로그래밍하기도 정말 쉬운 쿼리입니다. 현재 페이지 번호만 넘겨주면 모든 것이 가능합니다. 가장 큰 장점이 바로 개발하기 편하다는 것이 겠고, 사용자의 웹접근 액션과도 상당히 잘 맞아 떨어집니다. 사람들은 10페이지 이상은 잘 보지 않으려는 경향이 있기 때문입니다.

NOT IN 쿼리는 생각보다 좋은 쿼리라는 것을 일단 말씀 드립니다. 단 조건은 INDEX를 잘 설정해줬다는 조건이 붙습니다.

 

게시판 등을 개발할 때 전체 게시물 수를 구해오는데 가장 많이 쓰는 쿼리문이 SELECT COUNT(*) FROM TBL입니다. 페이지 바로 가기 버튼을 위해서도 필요하고 게시물 번호를 붙히는 데도 쓰이기 때문에 쓰는 경우가 많습니다.

헌데 이 쿼리문 속도가 상당히 늦습니다. 100만건을 조회할 경우 1초가 넘어가 버리는 무식한 쿼리입니다. 야야~ 그럼 IDEX행을 가져와봐... 라고 하실 것 같습니다. SELECT COUNT(ID) FROM TBL ... 허나 애석하게 속도가 똑같습니다.

그리고 COUNT함수는 가능하면 (*)를 사용하시기 바랍니다. 이것이 정확한 방법입니다. COUNT(*)에서 속도향상을 위한 방법은 솔직히 말씀드려서 없습니다.

가장 좋은 방법은 테이블 하나를 만들어서 데이타 입력/삭제시마다 업데이트 하면서 게시물 수를 저장해 놓는 방법입니다. MSSQL 내에서는 트리거라는 기능을 제공합니다. INPUT/DELETE 시 UPDATE TBL_SETTING set TBL_COUNT = xxx 뭐 이런 식으로 짜 놓으면 되겠죠.

전체 게시물 수를 가져올 때는 되도록이면 트리거를 쓰거나 프로그램을 통해 정보를 저장하는 테이블에 업데이트하고 이 자료를 페이징시 가져오는 것이 성능을 위한 좋은 방법입니다.

1만건 이하라면 COUNT(*)를 쓰던 NOT IN을 쓰던 별 지장이 없다는 게 제 생각입니다. 고로, 자꾸 써먹어도 좋은 쿼리 들임을 일단 알려드립니다.

 

#5 성능향상에 가장 좋은 방법

1000만건을 테스트 해보지는 않았지만, 1페이지와 100만 페이지가 같은(해보진 않았죠^^)-혹은 비슷한- 성능을 보이는 쿼리는 다름 아닌 NOT IN보다 훨씬 더 간결한 쿼리입니다.

SELECT TOP 11 ID, subject, contents FROM TBL where ID <= 현재페이지 최상위 ID (order by ID DESC)

이 쿼리에서 가장 중요한 것은 ID가 클러스터드 인덱스로 ID를 설정하고 내림차순으로 지정되어 있어야 한다는 것입니다.

아무리 많은 글들도 0.1초안에 해결될만한 가장 성능이 좋은 쿼리문입니다. 동접자수 엄청나고 글 수가 많다면 이방법 이외의 방법은 사용하지 마시기 바랍니다.

허나 장점이 있으면 단점도 있습니다. 이 쿼리를 사용할 경우 ID값에 바로 접근하긴하기 때문에

이전 1 2 3 4 5 6 7 8 9 10 다음 <- 이와 같은 구성이 불가능하다는 것입니다.

그래서 TOP 10이 아닌 11을 사용한 것입니다. 1부터 10까지 구성은 힘들지만 다음페이지 버튼은 가능하기 때문입니다. 갯수가 11개면 다음 페이지가 있다는 이야기가 되며, 다음페이지의 최상위 ID값도 가져올 수 있게 됩니다.

어쨌거나 위 쿼리는 성능에 있어서는 더이상 좋을 수 없는 쿼리입니다. 분명 글이 많고 사용자 액션이 단순한 사이트라면 반드시 고려해보셔야 할 쿼리입니다. 이전 페이지 구현은 프로그램적으로 머리를 좀 굴려야 할 부분이긴 합니다.

어짜피 다음 페이지 버튼을 눌러야만 가능하니깐 이전 페이지의 ID값은 무조건 가지고 갈 수 있습니다. POST방식으로 이전 페이지 정보를 계속 넘기는 방법도 괜찮은 방법일 것입니다.

 

SELECT TOP 10 ID FROM TBL where ID > 현재페이지 최상위 ID order by ID ASC 를 어쩔 수 없이 쓰는 것도 한 방법이겠구요. 그래도 다른 쿼리들보다는 빠른 방식이니깐요. <- 이건 저도 테스트 해보진 않았습니다.

 

#6. 사용자 편의성도 좀 생각해 보자

대부분 웹사이트에서는 NOT IN쿼리가 좋은 방법입니다. 사용자 편의성에 있어서 좋은 선택이니깐요.

이전 1 2 3 4 5 6 7 8 9 10 다음 <- 이게 얼마나 편한 방법입니까^^; 그리고 사람들은 10페이지 이상 조회를 거의 하지 않기도 합니다.

성능을 생각한다면 #5번의 방법이 정말 좋은 방법이지요. 다만 사용자 편의를 위한 인터페이스 구현은 사실상 불가능 합니다. 이전 페이지 구현도 쉽지 않죠.

목표가 생겼습니다.

이전 1 2 3 4 5 6 7 8 9 10 다음

이 기능을 한번 구현해 보죠. 약간 성능 저하가 있더라도... 전체 NOT IN보다는 훨씬 더 빠르게 한다는 목표를 가지고...

일단 쿼리를 하나 보죠.

SELECT TOP pageSize*10+1 ID from TBL where ID <= 1페이지 11페이지 21페이지 등 각 1페이지의 처음 ID

이 쿼리는 페이지 바로가기 버튼 구현을 위한 쿼리입니다.

페이지 사이즈가 10개라고 하면 101개를 가져옵니다. 101개면 너무 많지 않냐 하겠지만 적은 갯수입니다.^^

컬럼이 하나밖에 없기 때문에 속도 저하가 거의 없는 쿼리죠.

이 결과를 가지고 1 2 3 4 5 6 7 8 9 10 다음 버튼 구현이 가능합니다. 이전 버튼 구현은 역시 약간 복잡하죠?

PageInfo = rs.getrows() 등의 좋은 메소드 등을 통해 배열로 만든 후 이 기능을 구현하는 것이 가장 좋은 방법일거라 생각됩니다.

 

SELECT TOP 10 ID, subject, contents from TBL where ID not in(SELECT TOP pageSize*(현재페이지의한자리숫자-1 / 0일때는 10) ID from TBL  where ID <= 페이지 11페이지 21페이지 등 각 1페이지의 처음 ID order by ID DESC)  and ID <= 페이지 11페이지 21페이지 등 각 1페이지의 처음 ID order by ID DESC

 

이 쿼리는 실제로 글을 뿌려주는 쿼리입니다. NOT IN이 쓰였네요. 하지만 10페이지 단위로 끊어서 10페이지 글 내에서 NOT IN을 사용하기 때문에 항상 빠른 속도를 내줄 수 있는 쿼리입니다.

페이지당 글 수가 아무리 많아도 100개 이하가 대부분이기 때문에 10페이지 단위로 끊는다고 해도 1000개의 글 내에서 모든 작업이 이루어지기 때문에 성능 저하는 거의(아예) 없다고 보시면 됩니다. 1000개정도 레코드는 아무것도 아니지요.

 

다만 걸리는 것은 페이지 바로 가기 버튼을 구현하기 위해 비슷한 쿼리를 두번 날렸기 때문에 두배의 비용이 든다는 거겠지요.

 

#7. 검색에 대한 이야기

검색 속도를 위한 가장 좋은 방법은 고가의 검색 엔진을 사용하는 것입니다. 검색엔진에 DB를 설정하고 URL 저장 방법만 설정해 놓고 스케쥴링만 해 놓으면 검색엔진은 알아서 DB를 검색하고 고쳐진 값에 대해서 URL 링크를 인덱싱해 놓습니다.

속도도 빠르고 한글의 경우 형태소 분석기를 통해 별에 별 검색도 가능하며 서비스 측면에서는 하일라이트 생성기등을 통해 사용자 편의성을 제공해주고... 뭐... 문제는 쩐이군요^^;

MSSQL에서 우리는 like '%xxx%' 검색을 많이 활용하게 됩니다.

SELECT ID, subject, contents from TBL where subject like '%xxx%'

이 쿼리는 xxx를 가지는 모든 subject 컬럼에 대해 검색을 하게 됩니다. 그럼 어떻게 해야 할까요. 넵~ 인덱스를 설정해야 합니다. subject에 대해서 넌클러스터드 인덱스를 설정해 주어야 합니다.

subject 는 varchar(255)형입니다. 그렇기 때문에 인덱스 설정이 가능합니다.

 

-> 몇년만에 수정합니다. 잘못된 정보네요^^; like 'xxx%'일때만 인덱스 타요~ 참고하시구요. 너무 예전에 쓴 글인데 여전히 이렇게 읽으실 줄이야. 에구구구... 이 이야기는 추후 다시 해야 할 것 같네요.

 

 

그럼 contents like '%xxx%'는?

헌데 contents가 text형이거나 varchar(max) (이건 2005에서 지원)라면?...

불행히도 인덱스를 줄수가 없습니다. MSSQL은 그다지 많은 인덱스 공간을 지원해주지 않습니다.

이경우 가능하면 input쪽에 varchar(900)정도 만큼만 글을 입력하도록 제한하거나 varchar(900)을 몇개 더 만들어서 DB저장시 나누어서 넣어주는게 좋습니다.

편법이고 지저분한 방법입니다.^^; 그래도 뭐 속도 향상이 있다면야... 모두들 어쩔 수 없이 text형도 검색을 하지만, 좋은 방법이 아닙니다. 글이 1만개만 넘어가다 상당한 부하가 걸릴 거라 생각됩니다.

넌클러스터드 인덱스만이라도 걸려 있다면, 성능은 무척 좋아집니다.

하지만 너무 방법이 지저분 하네요.

더좋은 방법이 있겠죠? MSSQL은 이런 경우를 위해 풀텍스트검색서비스를 지원합니다. varchar(MAX)나 text형 등을 시중의 검색엔진과 비슷한 방식으로 인덱싱하고 검색할 수 있는 방법은 제공합니다. 속도가 그렇게 좋지는 못합니다만...  형태소 분석기도 들어 있고 유사어 검색도 가능하고 정확도 정렬도 가능합니다. 다만 문제는 속도가 생각처럼 나오지는 않는 다는 것입니다. 특히 정확도 정렬을 위한 정렬의 경우 100만건 이상으로 테스트시 1초가 넘어가더군요.

그리고 MSSQL 2000에서 한글은 제대로 지원되지 않았습니다. 2005에서 한글 지원이 되는데... 실제로 띄어쓰기를 하지 않아도 검색이 되는 정도를 확인하였습니다. 동의어 검색도 가능하다고 하는데... 저역시 많은 테스트가 필요할 것 같습니다.

2000에서는 전혀 안쓰는 기능이었지만, 2005에서는 충분히 활용가치가 있을 것 같네요. 다만 호스팅 업체에서 이 기능을 지원하지 않는 다는 것이 가장 큰 문제입니다.^^; 인덱싱 속도는 꽤 빠르나 하드디스크를 많이 차지하기 때문에, 그리고 인덱싱시 꽤 부하를 주기 때문에 지원하지 않는 것 같으며, 2000의 경우 한글 인덱싱 자체가 잘 안되기 때문에 지원을 하지 않는 것 같습니다.

다만 MSSQL 2005라면 프로젝트에 충분히 쓸 수 있을 것도 같습니다. 제가 이번에 활용해보도록 하겠습니다.

상용검색엔진에 비하면 못하겠지만 어느정도 흉내를 내주고 CONTAINS(TABLE)/ FREETEXT(TABLE)등의 4개의 함수를 통해 SQL쿼리문 내에서 사용하기 때문에 개발하기가 수월합니다.

풀텍스트 검색엔진에 대한 이야기는 또 다음에 계속 하도록 하겠습니다.

 

 

정리;

속도 향상을 위해 가장 중요한 것은 바로 INDEX 설정!;

 

글 가져다 나르는 것을 금지합니다.

 

ps. 2011년 MS SQL 2005 이상이면, .net에서 LINQ가 만들어주는 SQL 문이 있는데요.

 

rownum() 함수 써서 하는게 속도가 좋네요.

 

참고하시고 시간 날때 정리할꼐요



출처 : http://blog.naver.com/PostView.nhn?blogId=tank51882&logNo=60144213744&redirect=Dlog&widgetTypeCall=true


통상적으로 테이블 로우수를 가지고 올때 아래와 같이 많이 사용 할 것이다. 

 

select count(1) from 테이블명

 

테이블 로우수가 얼마되지 않은 자료를 가지고 올때는 위와같이 사용해도 특별히 문제점은 없다.

 

하지만 대용량으로 가면갈수록 전체 테이블에 로우수를 확인하는데도 초단위 이상에 시간이 소요가 된다.

 

덩치가 좀 되는 테이블 로우수는 어떻게 취하는게 효율적일까? 그 해답은 아래와 같다.

 

SELECT DISTINCT MAX(idx.rows) 
FROM SYSINDEXES as idx INNER JOIN SYSOBJECTS AS obj

ON (idx.id = obj.id)
WHERE (obj.type = 'U') AND (obj.name = '테이블명')

 

쿼리를 보면 알겠지만 시스템 테이블을 활용하여 Row Count를 취하는 방법이다.

 

비교된 결과물이 있어야 화아악~ 와 닿겠죠잉~ ^^

 

제가 보유하고 있는 테이블 중에 Row Count가  54,602,856 인것을 예로 들면

 

먼저 흔히들 사용하는 select count(1) from 테이블명    쿼리로 하였을 때 결과다

 

결과값을 가지고 오는 4분 37초가 소요가 되었다.

 



 

반면 

SELECT DISTINCT MAX(idx.rows) 
FROM SYSINDEXES as idx INNER JOIN SYSOBJECTS AS obj

ON (idx.id = obj.id)
WHERE (obj.type = 'U') AND (obj.name = '테이블명') 

 



 

서프라이즈~ ^^  이 얼마나 놀라운가 시스템 테이블에 정보를 이용하여 실행과 함께 결과물이 나왔다.

 

이것을 실행결과로 비교해보면 100:0 에 실행 계획이 나온다.

 



 

나 역시 ms sql에서 테이블 로우수를 빨리 취하는법에 대해 알고는 있었지만 사용은 하지 않는다.

 

왜? 위에 쿼리보다 아래쿼리가 기니까~ ㅋ

 

하지만 대용량 서버에서 로우수를 취할 때는 유용하게 사용될 수 있을것이다.

 

더불어 해당 DB에 모든 테이블에 로우수를 가지고 오는 방법으로는 아래 쿼리를 사용하면 될것이다.

 

select obj.name, max(idx.rows)
from sysindexes as idx
inner join sysobjects as obj on (idx.id = obj.id)
where (obj.type = 'U') 
group by obj.name

 

참고로 sysobject와 sysindexes layout 정보를 첨부해본다.

 

이런 된장~ 포스팅을 하고 검색을 좀 해보니 프로시저로 제공이 된다.. 뜨벌~

 

execute sp_tables_info_rowset '테이블명'

 

나 지금 모한거니? ㅠ,.ㅜ

 

[sysobject]

열 이름데이터 형식설명

name

sysname

개체 이름

id

int

개체 ID

xtype

char(2)

개체 유형입니다. 다음 개체 유형 중 하나일 수 있습니다.

AF = 집계 함수(CLR)

C = CHECK 제약 조건

D = 기본값 또는 DEFAULT 제약 조건

F = FOREIGN KEY 제약 조건

L = 로그

FN = 스칼라 함수

FS = 어셈블리(CLR) 스칼라 함수

FT = 어셈블리(CLR) 테이블 반환 함수

IF = 인라인 테이블 함수

IT = 내부 테이블

P = 저장 프로시저

PC = 어셈블리(CLR) 저장 프로시저

PK = PRIMARY KEY 제약 조건(K 유형)

RF = 복제 필터 저장 프로시저

S = 시스템 테이블

SN = 동의어

SQ = 서비스 큐

TA = 어셈블리(CLR) DML 트리거

TF = 테이블 함수

TR = SQL DML 트리거

TT = 테이블 유형

U = 사용자 테이블

UQ = UNIQUE 제약 조건(K 유형)

V = 뷰

X = 확장 저장 프로시저

uid

smallint

개체 소유자의 스키마 ID입니다.

이전 버전의 SQL Server에서 업그레이드한 데이터베이스의 경우 스키마 ID는 소유자의 사용자 ID와 동일합니다.

중요:
다음 SQL Server DDL 문 중 하나를 사용하는 경우 sys.sysobjects 대신 sys.objects카탈로그 뷰를 사용해야 합니다.

CREATE | ALTER | DROP USER

CREATE | ALTER | DROP ROLE

CREATE | ALTER | DROP APPLICATION ROLE

CREATE SCHEMA

ALTER AUTHORIZATION ON OBJECT

사용자 및 역할 수가 32,767을 초과하는 경우 오버플로되거나 NULL을 반환합니다.

자세한 내용은 SQL Server 시스템 카탈로그 쿼리를 참조하십시오.

info

smallint

정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다.

status

int

정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다.

base_schema_ver

int

정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다.

replinfo

int

정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다.

parent_obj

int

부모 개체의 개체 ID입니다. 예를 들어 트리거 또는 제약 조건인 경우 테이블의 ID입니다.

crdate

datetime

개체를 만든 날짜입니다.

ftcatid

smallint

전체 텍스트 인덱싱을 위해 등록된 모든 사용자 테이블의 경우 전체 텍스트 카탈로그 식별자이며, 등록되지 않은 모든 사용자 테이블의 경우 0입니다.

schema_ver

int

테이블의 스키마가 변경될 때마다 증가하는 버전 번호입니다. 항상 0을 반환합니다.

stats_schema_ver

int

정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다.

type

char(2)

개체 유형입니다. 다음 값 중 하나를 사용할 수 있습니다.

AF = 집계 함수(CLR)

C = CHECK 제약 조건

D = 기본값 또는 DEFAULT 제약 조건

F = FOREIGN KEY 제약 조건

FN = 스칼라 함수

FS = 어셈블리(CLR) 스칼라 함수

FT = 어셈블리(CLR) 테이블 반환 함수 IF = 인라인 테이블 함수

IT = 내부 테이블

K = PRIMARY KEY 또는 UNIQUE 제약 조건

L = 로그

P = 저장 프로시저

PC = 어셈블리(CLR) 저장 프로시저

R = 규칙

RF = 복제 필터 저장 프로시저

S = 시스템 테이블

SN = 동의어

SQ = 서비스 큐

TA = 어셈블리(CLR) DML 트리거

TF = 테이블 함수

TR = SQL DML 트리거

TT = 테이블 유형

U = 사용자 테이블

V = 뷰

X = 확장 저장 프로시저

userstat

smallint

정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다.

sysstat

smallint

정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다.

indexdel

smallint

정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다.

refdate

datetime

정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다.

version

int

정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다.

deltrig

int

정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다.

instrig

int

정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다.

updtrig

int

정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다.

seltrig

int

정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다.

category

int

게시, 제약 조건 및 ID에 사용됩니다.

cache

smallint

정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다.

 

 

[sysindexes]

열 이름데이터 형식설명

id

int

인덱스가 속한 테이블의 ID입니다.

status

int

시스템 상태 정보입니다.

정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다.

first

binary(6)

첫 페이지 또는 루트 페이지에 대한 포인터입니다.

indid가 0일 경우 사용되지 않습니다.

NULL = indid가 1보다 큰 경우 인덱스가 분할됩니다.

NULL = indid가 0 또는 1일 때 테이블이 분할됩니다.

indid

smallint

인덱스의 ID입니다.

0 = 힙

1 = 클러스터형 인덱스

>1 = 비클러스터형 인덱스

root

binary(6)

indid >= 1인 경우 root는 루트 페이지에 대한 포인터입니다.

indid가 0일 경우 사용되지 않습니다.

NULL = indid가 1보다 큰 경우 인덱스가 분할됩니다.

NULL = indid가 0 또는 1일 때 테이블이 분할됩니다.

minlen

smallint

행의 최대 크기입니다.

keycnt

smallint

키 수입니다.

groupid

smallint

개체가 만들어진 파일 그룹의 ID입니다.

NULL = indid가 1보다 큰 경우 인덱스가 분할됩니다.

NULL = indid가 0 또는 1일 때 테이블이 분할됩니다.

dpages

int

indid = 0 또는 indid = 1인 경우 dpages는 사용한 데이터 페이지의 수입니다.

indid가 1보다 작은 경우 dpages는 사용한 인덱스 페이지의 수입니다.

0 = indid가 1보다 큰 경우 인덱스가 분할됩니다.

0 = indid가 0 또는 1인 경우 테이블이 분할됩니다.

행 오버플로가 발생할 경우 정확한 결과가 반환되지 않습니다.

reserved

int

indid = 0 또는 indid = 1인 경우 reserved는 모든 인덱스 및 테이블 데이터에 할당된 페이지의 수입니다.

indid가 1보다 작은 경우 reserved는 인덱스에 할당된 페이지의 수입니다.

0 = indid가 1보다 큰 경우 인덱스가 분할됩니다.

0 = indid가 0 또는 1인 경우 테이블이 분할됩니다.

행 오버플로가 발생할 경우 정확한 결과가 반환되지 않습니다.

used

int

indid = 0 또는 indid = 1인 경우 used는 모든 인덱스 및 테이블 데이터용으로 사용된 총 페이지의 수입니다.

indid가 1보다 작은 경우 used는 인덱스용으로 사용된 페이지의 수입니다.

0 = indid가 1보다 큰 경우 인덱스가 분할됩니다.

0 = indid가 0 또는 1인 경우 테이블이 분할됩니다.

행 오버플로가 발생할 경우 정확한 결과가 반환되지 않습니다.

rowcnt

bigint

indid = 0 및 indid = 1을 기준으로 하는 데이터 수준 행 개수입니다.

0 = indid가 1보다 큰 경우 인덱스가 분할됩니다.

0 = indid가 0 또는 1인 경우 테이블이 분할됩니다.

rowmodctr

int

테이블에 대해 통계를 마지막으로 업데이트한 이후에 삽입, 삭제 또는 업데이트된 행의 총 수를 셉니다.

0 = indid가 1보다 큰 경우 인덱스가 분할됩니다.

0 = indid가 0 또는 1인 경우 테이블이 분할됩니다.

SQL Server 2005 이상 버전에서 rowmodctr은 이전 버전과 완전히 호환되지는 않습니다. 자세한 내용은 주의를 참조하십시오.

xmaxlen

smallint

행의 최대 크기입니다.

maxirow

smallint

리프가 아닌 인덱스 행의 최대 크기입니다.

SQL Server 2005 이상 버전에서 maxirow는 이전 버전과 완전히 호환되지는 않습니다.

OrigFillFactor

tinyint

인덱스가 만들어질 때 사용되는 원래 채우기 비율 값입니다. 이 값은 유지 관리되지 않지만 인덱스를 다시 만들어야 하거나 사용한 채우기 비율 값을 기억할 수 없는 경우에 유용합니다.

StatVersion

tinyint

0을 반환합니다.

정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다.

reserved2

int

0을 반환합니다.

정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다.

FirstIAM

binary(6)

NULL = 인덱스가 분할됩니다.

정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다.

impid

smallint

인덱스 구현 플래그입니다.

0을 반환합니다.

정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다.

lockflags

smallint

인덱스에 대해 고려된 잠금 세분성을 제약하는 데 사용합니다. 예를 들어 잠금 비용을 최소화하기 위해 일반적으로 읽기 전용인 조회 테이블을 테이블 수준의 잠금만 수행하도록 설정할 수 있습니다.

pgmodctr

int

0을 반환합니다.

정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다.

keys

varbinary(816)

인덱스 키를 구성하는 열의 열 ID 목록입니다.

NULL을 반환합니다.

인덱스 키 열을 표시하려면 sys.sysindexkeys를 사용하십시오.

name

sysname

인덱스 또는 통계의 이름입니다. indid가 0인 경우 NULL을 반환합니다. 응용 프로그램을 수정하여 NULL 힙 이름을 찾습니다.

statblob

image

통계 BLOB(Binary Large Object)입니다.

NULL을 반환합니다.

maxlen

int

정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다.

rows

int

indid = 0 및 indid = 1을 기준으로 하는 데이터 수준 행 개수이며 indid가 1보다 작은 경우에 값이 반복됩니다.

 


+ Recent posts