프로그램을 실행시키면 현재 사용중인 프로파일과, 경로를 자동으로
읽어옵니다. Speed Up My Firefox! 버튼만 눌러주면
됩니다. 단, 주의하실 점은 반드시 모든 파이어폭스 창을 닫은 상태로
실행시키셔야 합니다. 파이어폭스가 열려 있으면 에러가 뜨면서 실행이
중지됩니다.
Here’s code for finding the location of your user in the iPhone 3.0 version of Safari:
<script type="text/javascript">
if (navigator.geolocation) {
/* geolocation is available */
alert("geolocation is available");
navigator.geolocation.getCurrentPosition(foundLocation, noLocation);
} else {
alert("I'm sorry, but geolocation services are not supported by your browser.");
}
function foundLocation(position)
{
var lat = position.coords.latitude;
var long = position.coords.longitude;
alert('Found location: ' + lat + ', ' + long);
}
function noLocation()
{
alert('Could not find location');
}
</script>
인터넷 익스플로러6에서 absolute 등으로 부유된 div가 select에 가려지는 현상에 곤욕을 치루는 경우가 많다. IE6은 div보다
select를 우선으로 처리하기 때문인지라 자바스크립트를 사용해 div가 부유될 경우 select를 강제로 숨겨주는 등의 기법이 알려져
있다.
▲ 일반 브라우저에서 정상 출력되는 모습(좌) / IE6에서 select에 가려진
현상(우)
하지만 css만으로도 div가 select에 가려지지 않게 만들 수 있다. 해답은 비어있는 iframe 을
부유된 div와 같은 위치로 넣으면 된다는 것.
</fieldset> <fieldset> <legend>Conditions</legend> <div class="infos">Checking this box indicates that you accept terms of use. If you do not accept these terms, do not use this website : </div> <label> <span class="checkbox">I accept terms of use : </span> <input class="validate[required] checkbox" type="checkbox" id="agree" name="agree"/> </label> </fieldset> <input class="submit" type="submit" value="Validate & Send the form!"/> <hr/> </form>
ex2)
var w = parseInt(top.document.getElementById(id).style.width);
var h = parseInt(top.document.getElementById(id).style.height);
var window_left = (screen.availWidth-w)/2;
var window_top = (screen.availHeight-h)/2;
1. 파워포인트 파일 열기
2. 메뉴에서 "파일" - "다른 이름으로 저장" 클릭
3. "다른 이름으로 저장" 윈도우에서 "도구" 메뉴에서(모두 활용하기)
4. 일단 첫번째 체크 사항!! "그림 압축" 선택
5. "적용대상" - "문서에 있는 모든 그림" 선택
6. 출력할 필요가 없을 경우 "해상도 변경" - "웹/화면" 선택
7. "옵션" - "그림 압축, 잘려진 그림 영역 삭제" 선택
8. "확인" 클릭
9. 그림압축 경고창이 뜨면 "적용" 클릭
10. 저장할 새로운 이름 지정
11. "저장" 클릭
mysql>
EXPLAIN SELECT * from user;
EXPLAIN SELECT select_options;
각 칼럼의 의미
* table - 사용한 테이블. 조인일 경우는 행이 여러 개로 나온다.
*
type - 가장 중요한 것 중에 하나이며, 조인이 사용되었는지 말해준다. 가장 좋은 타입부터 가장 나쁜 타입은
system, const, eq-ref, ref, range, index, all 이다. Type에 all이나 index, range 등이 보일
경우는 쿼리가 그다지 빠르지 않다는 것을 의미한다.
system : 테이블이 하나의 레코드만 가지는 경우
const : 테이블에 조건을 만족하는 레코드가 하나일 때, 상수
취급
eq_ref : 인덱스가 UNIQUE이거나 PRIMARY KEY인 경우의 조인으로 const를 제외한 조인 중 가장 좋은
형태
ref : eq_ref와 다른 점은 UNIQUE나 PRIMARY KEY가 아닐 경우 사용한다는 것.
range : 조건에
레코드의 범위가 주어진 조인.
index : all 형태와 비슷하며, 인덱스를 사용한다.
all : 모든 레코드를
스캔한다.
* possible_keys - 사용 가능한 키(인덱스)
* key -
사용하고 있는 키(인덱스)
* key_len - 키가 사용된 길이. 작을수록 좋다(int는 4바이트,
char(10)은 10바이트를 차지한다. 테이블에서 데이터형의 결정은 되도록이면 int나 smallint, medianint를 사용하는 것이
좋다).
ref - 칼럼이나 상수(const)가 사용되었는지 말해준다.
rows - 인덱스 범위를 나타낸다. 작을수록 역시 빠르다.
Extra - 정보- "using temporary"나 "using filesort"는 가장 좋지 않다.
distinct : 조건을
만족하는 레코드를 찾았을 때 같은 조건을 만족하는 또 다른 레코드가 있는지 검사하지 않음.
not exist : left join 조건을
만족하는 하나의 레코드를 찾았을 때 다른 레코드의 조합은 더 이상 검사하지 않는다.
range checked for each record
: 최적의 인덱스가 없는 차선의 인덱스를 사용한다는 의미.
using filesort : mysql이 정렬을 빠르게 하기 위해 부가적인
일을 한다. (안쓰는게 좋다.)
unsing index : select 할때 인덱스 파일만 사용
using temporary : 임시
테이블을 사용한다. order by 나 group by 할때 주로 사용 (안쓰는게 좋다.)
where used : 조건을 사용한다는 의미.
큰 테이블(2G가 넘는)이 필요하다면, 알파나 스팍 또는 IA64 등의 64bit 하드웨어를 고려해 보는 게 좋다. MySQL은 내부적으로
64bit 정수를 많이 사용하고 있으므로, 64bit CPU를 사용하면 좀더 나은 퍼포먼스를 기대할 수 있다.
거대한 데이터베이스를 위한
최적화는 보통 램, 빠른 디스크, CPU 순으로 진행된다.
더 많은 램은 사용되는 대부분의 key 페이지들을 램에 보관함으로써 빠른
key 갱신을 가능하게 한다.
안전한 트랜잭션을 사용하지 않거나 큰 디스크를 사용하고 파일 검사를 오랫동안 하는 일을 피하고 싶다면
UPS를 사용하여 전원 오류가 발생한 경우에도 시스템을 안전하게 종료시킬 수 있도록 하는 것도 좋은 생각이다.
하나의 전용 데이터베이스
서버를 가진 시스템이라면 1G 이더넷을 고려해 볼 필요가 있다. 네트워크 지연은 처리능력만큼 중요하다.(Latency is as
important as throughput.)
디스크 최적화
시스템, 프로그램, 임시 파일들을 위한 전용 디스크를 갖춰라. (내용이) 자주 변경되는 경우라면 갱신 기록과 트랜잭션 기록 파일을 별도의
디스크에 배치한다.
데이터베이스 디스크에 있어서는 빠른 탐색 시간(seek time)이 요건이다. 큰 테이블에서 하나의 레코드를 찾기
위해 소요되는 탐색 횟수는 다음과 같이 추정해 볼 수 있다.
예를 들어, 500,000개의 레코드를 가지고 있고 medium int 형 필드로 인덱싱하고 있는 테이블의 경우라면 log(500000)
/ log(1024/3*2/(3+4))+1 = 4 번의 탐색이 필요하다. 여기서 인덱스는 500,000 * 7 * 3/2 = 5.2M 정도의
크기가 될 것이다. 실제로는 대부분의 블록들이 버퍼에 저장되므로 아마도 1~2번 정도의 탐색이 필요하게 된다.
쓰기의 경우 새로운 키를
넣을 위치를 찾기 위해 위에서처럼 4번의 탐색이 필요하지만, 통상적으로 인덱스를 갱신하기 위해 2번의 탐색이 더 필요하다.
매우 큰 데이터베이스에 경우, 디스크 탐색 속도에의해 성능이 좌우되는데, 탐색 수는 더 많은 데이터를 얻을 때마다 N log N 씩
증가한다.
데이터베이스들과 테이블들을 다른 디스크들에 분할해 넣어라. MySQL에서는 이를 위해 심볼릭 링크를 사용할 수 있다.
Striping disks(RAID 0와 같은)는 읽기와 쓰기 양면에서 처리능력을 증가시킨다.
미러링을 동반하는 Striping
disk(RAID 0+1)는 읽기/쓰기 성능을 향상시키고 안전성을 제공한다. 쓰기는 약간 느리다.
임시파일 또는 쉽게 갱신될 수도 있는 데이터에 대해서 미러링이나 RAID(RAID 0는 예외)를 사용하지 않는다.
Linux를 사용한다면 부팅할 때 hdparm -m16 -d1 명령을 디스크에 적용하여 다중 섹터 읽기/쓰기와 DMA 사용이 가능하도록
한다. 이는 반응 시간을 5~50%까지 증가시킨다.
Linux를 사용한다면 디스크를 마운트할 때 async(기본값이다)와 noatime
옵션을 부여하여 마운트한다.
일부 특정 응용프로그램의 경우 아주 특수한 테이블을 램디스크에 저장하는 것도 한 방법이 된다. 그러나 보통은 필요 없다.
운영체제 최적화
스왑을 제거한다. 메모리 문제가 있다면 시스템이 적은 메모리를 사용하도록 설정하기 보다는 메모리를 증설하는 것이 좋다.
데이터에 대해서 NFS 디스크를 사용하지 않는다. (NFS locking 문제에 봉착할 수 있다.)
시스템과 SQL 서버를 위해
open file 한계 수치를 증가시킨다. (safe_mysql 스크립트에 ulimit -n #을 추가한다.)
프로세스와 쓰레드의 개수 제한을 늘려준다.
상대적으로 큰 테이블을 사용할 일이 드물다면, 파일시스템이 파일을 여러 실린더에 분산시켜 저장하지 않도록 설정한다.(솔라리스)
큰
파일을 지원하는 파일시스템을 사용한다.(솔라리스)
어떤 파일시스템을 사용하는 것이 좋을지 선택한다. 리눅스의 Reiserfs 는 파일
열기, 읽기, 쓰기에 있어서 (ext2보다) 빠르다. 파일 검사도 단지 수 초 밖에 안 걸린다.
API 선택
PERL
OS 와 데이터베이스들간의 이식성 우수하다.
빠른 프로토타이핑에 적합하다.
DBI/DBD 인터페이스를
사용하는 것도 한 방법이다.
PHP
PERL 보다 익히기 쉬운 언어다.
PERL 보다 자원을 적게 사용. 때문에 웹서버에 내장시키기에 좋다.
PHP4로 업그레이드하여 더 나은 속도를 얻는 것도 한 방편이다.
C
MySQL 본래의 인터페이스이다.
더 빠르고 더 많은 제어가 가능하다.
저 수준. 때문에 (프로그래머가) 더 많은
일을 해야 한다.
C++
고 수준. 코딩에 더 많은 시간이 필요하다.
(MySQL C++ API는) 여전히 개발 단계에 있다.
ODBC
윈도우즈와 유닉스에서 동작한다.
거의 대부분의 다른 SQL 서버로 이식 가능하다.
느리다. MyODBC는
단순한 pass-through 드라이버이지만 본연의 인터페이스에 비해 19% 정도 느리다.
같은 일을 수행하는 많은 다른 도구들이 있다. 작업을 어렵게 하는 한 가지는 많은 ODBC 드라이버들이 제각기 다른 부분에서 상이한
버그들을 가지고 있다는 점이다.
문제 발생 소지가 많다. 마이크로소프트는 정기적으로 인터페이스를 변경한다.
미래가
불확실하다.(마이크로소프트는 ODBC보다 OLE 쪽에 더 많은 비중을 두고 있다.)
JDBC
이론적으로 OS, 데이터베이스 간의 이식성이 우수하다.
(브라우저와 같은)웹 클라이언트 상에서 동작할 수 있다.
Python + others
좋을 것이다. 그러나 우리는 사용하지 않는다.
응용프로그램 최적화
우선은 문제 해결에 집중하는 것이 필요하다.
응용프로그램을 제작할 때 다음 중 무엇이 가장 중요한지를 결정하는 것이 필요하다:
속도
OS 간의 이식성
SQL 서버들 간의 이식성
persistent connection을 사용한다.
응용프로그램
측의 캐싱은 SQL 서버의 부하를 감소시킨다.
응용프로그램 상에서 쓰이지 않는 컬럼은 쿼리하지 않는다.
SELECT * FROM
table_name... 과 같은 쿼리를 사용하지 않는다.
응용프로그램의 모든 부분에 대하여 벤치마킹을 시도한다. 그러나 대부분의 노력을
부하의 가장 유력한 요인일 것 같은 부분의 응용프로그램들에 집중하는 것이 좋다. 이를 모듈 단위로 수행하면 발견한 병목구간을 빠른 '더미
모듈'로 대체하고 나서 다음 병목구간을 찾는 일로 넘어가는 식으로 일을 진행할 수 있다.
일련 작업 중에 많은 변경이 이루어진다면
LOCK TABLES을 이용한다. 예를 들면, 여러 개의 UPDATE 또는 DELETES 문장을 집합적으로 수행하는 경우 등.
이식성이 중요한 응용프로그램이라면
Perl DBI/DBD
ODBC
JDBC
Python (또는 범용 SQL
인터페이스를 가진 다른 언어들) 등을 사용한다.
모든 대상 SQL 서버들이 갖추고 있는, 또는 쉽게 다른 구문으로 모사할 수 있는 SQL
구문만 사용한다. www.mysql.com 의 crash-me 페이지를 보면 도움이 될 것이다.
다른 OS나 SQL서버들에
없는 기능들을 제공하기 위해 wrapper 프로그램을 제작하여 사용한다.
보다 빠른 속도가 요구된다면
병목구간(bottleneck)을 (CPU, 디스크, 메모리, SQL 서버, OS, API, 또는
응용프로그램에서) 찾아내서 제거하는 일에 집중한다.
더 빠른 속도와 유연성을 제공하는 MySQL의 확장기능을 사용한다.
SQL
서버에 관한 지식을 더 많이 습득하여 문제를 해결하기 위한 가장 빠른 SQL 구문을 사용하고 병목요소를 사전에 제거한다.
테이블
레이아웃과 쿼리들을 최적화한다.
select 속도를 증가시키기 위해 replication을 사용한다.
데이터베이스가 느린
네트워크로 연결되어 있다면, 압축된 클라이언트/서버 프로토콜을 사용한다.
응용프로그램의 초기 버전이 이식성에 있어서 부실하더라도 걱정할
필요 없다. 문제를 먼저 해결하고 나서 나중에 언제든지 최적화할 수 있다.(Don't be afraid to make the first
version of your application not perfectly portable; when you have solved your
problem, you can always optimize it later.)
MySQL 최적화
컴파일러와 컴파일 옵션을 충분히 고려하여 선택한다.
가장 훌륭한 MySQL 시작 옵션을 찾는다.
MySQL 매뉴얼을
찾아보고 Paul DuBois 의 MySQL 서적을 읽는다.
EXPLAIN SELECT, SHOW VARIABLES, SHOW
STATUS, SHOW PROCESSLIST 명령을 사용한다.
쿼리 옵티마이저가 동작하는 방식을 공부해 둔다.
테이블을
관리한다.(myisamchk, CHECK TABLE, OPTIMIZE TABLE)
MySQL 확장기능을 사용하여 속도를 증진시킨다.
특정 함수가 많은 곳에서 자주 사용될 것이라면 MySQL 사용자 정의 함수(UDF)로 직접 제작한다.
정말 필요한 경우가
아니라면, 테이블 수준 또는 컬럼 수준에서 GRANT 를 사용하지 않는다.
MySQL 고객 지원 서비스에 비용을 지불하고 문제 해결을
위한 도움을 받는다 :)
MySQL의 컴파일 및 설치
자신의 시스템에서 사용 가능한 최상의 컴파일러를 선택함으로 보통 10~30% 정도 성능 향상을 기대할 수 있다.
Intel 기반의 리눅스 시스템이라면 MySQL을 pgcc(펜티엄급에 최적화된 버전의 gcc)로 컴파일 한다. 그러나, (컴파일된)
바이너리는 인텔 펜티엄 CPU에서만 동장할 것이다.
MySQL 매뉴얼에서 권하는 플랫폼 별 최적화 옵션을 사용한다.
통상적으로 특정 CPU를 위한 본연의 컴파일러(Sparc을 위한 Sun Workshop과 같은)를 사용하면 gcc 보다 더 나은 성능을
기대할 수 있다. 그러나, 항상 그런 것은 아니다.
MySQL을 사용하려는 한 가지 문자셋만 지정하여 컴파일한다.
mysqld 실행파일을 정적으로 컴파일(--with-mysqld-ldflags=-all-static)하고 strip sql/mysqld
명령으로 최종 실행파일에서 디버그 코드를 제거한다.
MySQL이 C++ 예외처리를 하지 않으면, 즉 예외처리 지원 옵션을 빼고 컴파일하면
성능이 크게 향상된다.
운영체제가 네이티브 쓰레드(native thread)를 지원한다면 mit-pthreads 라이브러리 대신 네이티브 쓰레드를 사용하도록
한다.
생성된 실행파일을 MySQL 벤치마크 테스트로 테스트해 본다.
유지 보수
가능하면 정기적으로 OPTIMIZE table 을 실행한다. 이는 특히 자주 갱신되는 가변크기 레코드들에 대해 중요하다.
정기적으로 myisamchk -a 명령을 사용하여 테이블들의 key 분산 상태를 갱신한다. 이 작업을 수행하기 전에 반드시 MySQL을
셧다운해야 한다는 점을 잊지 않는다.
파일들이 조각난 상태라면 다른 디스크로 모두 복사하고 기존의 디스크를 깨끗이 한 후 다시 파일을 옮기는 일도 시도해 볼만한 가치가 있다.
문제가 발생한다면, 테이블을 myisamchk나 CHECK table 명령으로 검사한다.
MySQL의 상태를 mysqladmin
-i10 processlist extended-status 명령으로 모니터한다.
MySQL GUI 클라이언트를 사용하면 프로세스 목록과
상태를 다른 윈도우에서 모니터할 수 있다.
mysqladmin debug 명령을 사용해서 잠금(lock)과 성능에 관한 정보를 얻는다.
SQL 최적화
사용하는 것이 좋은 것에만 SQL을 사용하고 그렇지 않은 곳에서는 다른 것을 사용한다. SQL는 다음과 같은 곳에 사용한다.
WHERE 절에 의존하여 행을 찾는 경우
테이블들을 JOIN 할 경우
GROUP BY
ORDER BY
DISTINCT
다음과 같은 일에는 사용하지 않는다.
데이터(date 와 같은)의 유효성을 검증하는 경우
계산기로 사용
Tips
key를 폭 넓게 사용한다.
key는 검색에는 좋지만, key 컬럼에 대해 insert 나 update를 수행하는 데는 좋지 않다.
데이터를 제3의 보통 데이터베이스 형식(in the 3rd normal database form)으로 유지하되, 속도를 중시한다면 정보의
중복이나 요약 테이블(summary tables)을 생성하는 일을 기피할 필요는 없다.
큰 테이블에 대해서 GROUP BY를 남용하는 대신 그 테이블에 대한 요약 테이블을 생성하고 이 테이블에 대해 쿼리하는 것이 낫다.
UPDATE table set count=count+1 where key_column=constant 와 같은 문장은 매우 빠르다!
기록 테이블(log tables)에 관한 한, 정기적으로 요약 테이블을 만드는 것이 요약테이블을 그대로 두는 것 보다 나을 것이다.
INSERT에서 디폴트 값(default values)의 잇점을 십분 활용한다.
SQL 서버들 간의 속도 차이 (단위:초)
key 이용 2,000,000 행 읽기 NT Linux
mysql 367 249
mysql_odbc 464
db2_odbc 1,206
imformix_odbc 121,126
ms-sql_odbc
1,634
oracle_odbc 20,800
solid_odbc 877
sybase_odbc 17,614
위의 테스트는 MySQL의 경우 8M 캐시를 사용하도록 설정한 것이고 다른 데이터베이스들은 설치 기본값을 이용하였다.
중요한 MySQL 기동 옵션들
back_log 접속 수가 많다면 변경한다.
thread_cache_size 접속 수가 많다면 변경한다.
key_buffer_size 인덱스 페이지를 위한 풀(pool) 크기. 큰 수치를 지정하는 것도 가능하다.
bdb_cache_size BDB 테이블들에 의해 사용되는 레코드와 키 캐시 크기.
table_cache 많은 테이블을 가지고
있거나 동시 접속 수가 많다면 변경한다.
delay_key_write 모든 키 쓰기 동작을 버퍼링할 필요가 있다면 지정한다.
log_slow_queries 시간이 많이 걸리는 쿼리를 찾을 때 사용한다.
max_heap_table_size GROUP BY
절에서 사용된다.
sort_buffer ORDER BY 와 GROUP BY 절에서 사용된다.
myisam_sort_buffer_size REPAIR TABLE 문에서 사용된다.
join_buffer_size 키 없이
join 할 때 사용된다.
테이블 최적화
MySQL은 풍부한 상이한 컬럼 유형(type)들의 집합을 가지고 있다. 각 컬럼에 대해 가장 효과적인 유형을 선택하여 사용하는 것이
필요하다.
ANALYSE 프로시저는 테이블을 위한 최적의 컬럼 유형을 찾는데 도움이 될 것이다. SELECT * FROM table_name
PROCEDURE ANALYSE()
널 값을 저장하지 않을 컬럼은 NOT NULL 로 지정한다. 이는 특별히 인덱스 컬럼의 경우 중요하다.
ISAM 테이블들을 MyISAM 으로 변경한다.
가능하다면, 테이블을 고정된 테이블 형식으로 만드는 것이 좋다.
사용하지 않을 인덱스는 아예 만들지 않는다.
MySQL이 인덱스의 접두부(prefix)에 대해서 검색을 수행할 수 있다는 점을 활용한다.
INDEX (a, b) 로 되어 있다면, (a)에 대해 인덱싱할 필요는 없다.
길이가 긴 CHAR 형이나 VARCHAR 형이라면 해당 컬럼에 대해 인덱스를 생성하지 않고 그 컬럼의 접두부에 대해서만 인덱스를 생성하면
공간이 절약된다.
CREATE TABLE table_name (hostname CHAR(255) not null,
index(hostname(10)))
각 테이블을 위한 가장 효과적인 테이블 유형을 사용한다.
서로 다른 테이블들 중 동일한 정보를 가지는 컬럼들은 같은 유형, 같은
이름을 가지도록 정의한다.
MySQL이 데이터를 저장하는 방식
데이터베이스는 디렉토리로 저장된다.
테이블은 파일로 저장된다.
컬럼은 가변 길이나 고정 길이 유형으로 파일 안에 저장된다.
BDB 테이블에서 데이터는 페이지에 저장된다.
메모리 기반의 테이블도 지원된다.
데이터베이스와 테이블들은 다른 디스크로부터 심볼릭
링크될 수 있다.
Windows용 MySQL은 .sym 파일을 이용하여 데이터베이스에 대한 내부적인 심볼릭 링크를 지원한다.
MySQL 테이블 유형들
HEAP 테이블: 고정된 수의 레코드만 가지는 테이블로서 오직 메모리에만 저장되며 HASH 인덱스로 인덱스된다.
ISAM 테이블:
MySQL 3.22에서 사용된 구식 B-tree 테이블 유형이다.
MyISAM 테이블: ISAM 테이블의 새 버전으로 많은 확장 기능들을
가지고 있다.
바이너리 호환성
NULL 컬럼에 대한 인덱싱
가변 크기 테이블의 파편화(fragmentation)가 ISAM
테이블 보다 적음
거대 파일 지원
인덱스 압축 향상
키 통계 향상
더 향상되고 빠른 auto_increment 지원
Sleepycat의 Berkeley DB(BDB) 테이블: 안전한 트랜잭션 지원(BEGIN WORK / COMMIT | ROLLBACK)
MySQL 레코드 유형(ISAM/MyISAM 테이블과 관련하여서만)
MySQL은 모든 컬럼들이 고정 크기 유형이라면 (VARCHAR, BLOB, TEXT 컬럼이 없다면) 테이블을 고정 크기 테이블로
생성한다. 그렇지 않다면, 가변 크기 유형의 테이블로 만든다.
고정 크기 유형은 동적 크기 유형에 비해 속도가 빠르며 안전하다.
동적 크기 레코드 유형은 대개 보다 적은 공간을 사용하지만 테이블의 갱신이 자주 발생한다면 파편화가 가중되기 마련이다.
어떤 경우에는 주 테이블의 속도를 향상시키기 위해 모든 VARCHAR, BLOB, TEXT 컬럼들을 다른 테이블로 옮기는 것도 유용할 때가
있다.
myisampack(ISAM 테이블에서는 pack_isam)을 사용하면 읽기 전용, 압축된 테이블을 만들 수 있다.
느린 디스크를
사용할 때는 디스크 사용량을 최소화하는 것이 좋은 한 방법이 된다.
압축된 테이블은 더 이상 갱신되지 않는 로그 테이블 등에 사용하면 최상이다.
MySQL 캐시들 (한 번 적재되어 모든 쓰레드가 공유)
키 캐시: key_buffer_size, 기본값은 8M
테이블 캐시: table_cache, 기본값은 64
쓰레드 캐시:
thread_cache_size, 기본값은 0
호스트명 캐시: 컴파일할 때 변경 가능, 기본값은 128
메모리에 맵핑된
테이블(Memory mapped tables): 현재는 압축된 테이블을 위해서만 사용된다.
MySQL은 행(raw) 캐시를 가지고 있지
않다. 그러나, 운영체제에게 이 일을 시킬 수 있다!
MySQL 버퍼 변수들 (공유되지 않으며 실행 중 적재됨)
sort_buffer: ORDER BY / GROUP BY 절에서
record_buffer: 테이블을 스캔할 때
join_buffer_size: 키 없이 join을 수행할 때
myisam_sort_buffer_size: REPAIR
TABLE에서
net_buffer_length: SQL 문장을 읽을 때와 결과 값을 버퍼링할 때
tmp_table_size: 임시
결과값을 위한 HEAP-table-size
MySQL 테이블 캐시가 동작하는 방식
MyISAM 테이블의 열려 있는 각각의 인스턴스는 인덱스 파일과 데이터 파일을 사용한다. 만일 어떤 테이블이 두 개의 쓰레드에 의해
사용되거나 같은 쿼리에서 두 번 사용되면, MyISAM이 인덱스 파일은 공유하지만 데이터 파일은 또 하나의 인스턴스를 위해 추가로 열게 된다.
캐시 안의 모든 테이블이 사용 중이라면 그 캐시는 일시적으로 테이블 캐시 크기보다 커진다. 이러한 상황이 발생하면, 그 다음 방면된
테이블이 닫히게 된다.
mysqld 변수 Opend_tables를 검사해 보면 테이블 캐시가 너무 작은지 아닌지를 알 수 있다. 이 값이 높으면 테이블 캐시를
늘려줘야 한다!
MySQL 확장들 / 속도 증진 최적화
최적화된 테이블 유형을 사용한다.(HEAP, MyISAM, BDB 테이블)
데이터를 위한 최적의 컬럼을 사용한다.
가능한 한
고정 크기 레코드를 사용한다.
다른 잠금 유형(lock types)를 사용한다.(SELECT HIGH_PRIORITY, INSERT
LOW_PRIORITY)
Auto_increment
REPLACE (REPLACE INTO table_name VALUES
(...))
INSERT DELAYED
LOAD DATA INFILE / LOAD_FILE()
한번에 많은 레코드를
추가하기 위해서는 다중 레코드 INSERT를 사용한다.
SELECT INTO OUTFILE
LEFT JOIN, STRAIGHT
JOIN
IS NULL 과 접목된 LEFT JOIN 사용
일부 경우, ORDER BY 는 키를 사용할 수 있다.
하나의
인덱스에 있는 컬럼들만 쿼리할 경우에는 쿼리를 수행하기 위해 그 인덱스 트리만 사용하게 된다.
조인은 보통 subselect 보다
빠르다. (대부분의 SQL 서버들에서 그러하다.)
LIMIT
SELECT * from table1 WHERE a > 10
LIMIT 10, 20
DELETE * from table1 WHERE a > 10 LIMIT 10
foo IN (상수
목록) 구문은 매우 최적화되어 있다.
GET_LOCK() / RELEASE_LOCK()
LOCK TABLES
INSERT
와 SELECT 는 동시에 실행 될 수 있다.
작동하고 있는 서버로 읽어 들일 수 있는 UDF 함수들
압축된 읽기 전용 테이블들
CREATE TEMPORARY TABLE
CREATE TABLE .. SELECT
MyISAM 테이블을 RAID와 사용하면
하나의 파일을 여러개의 파일들로 나누어 일부 파일시스템의 2G 제한을 넘어서는 것이 가능하다.
Delayed_keys
리플리케이션(replication)
MySQL이 인덱스를 사용할 경우
>, >=, =, <, <=, 키에 대해 IF NULL 과 BETWEEN을 사용할 때
SELECT * FROM table_name WHERE key_part1=1 and key_part2 > 5;
SELECT *
FROM table_name WHERE key_part1 IS NULL;
와일드카드 문자로 시작하지 않는 LIKE 절을 사용할 때
SELECT * FROM table_name WHERE key_part1 LIKE 'jani%'
조인을 수행하면서 다른 테이블들로부터 레코드를 가져올 때
SELECT * from t1, t2 where t1.col=t2.key_part;
특정 인덱스에 대해서 MAX() 나 MIN() 값을 구할 때
SELECT MIN(key_part2), MAX(key_part2) FROM table_name where key_part1=10;
키의 접두부에 대해 ORDER BY 나 GROUP BY 절을 수행할 때
SELECT * FROM foo ORDER BY key_part1, key_part2, key_part3;
쿼리에 사용되는 모든 컬럼이 한 개의 키의 부분(part)일 경우
SELECT key_part3 FROM table_name WHERE key_part1=1;
MySQL이 인덱스를 사용하지 않을 경우
MySQL은 테이블 전체를 스캔하는 더 빠를 것이라고 판단되면 인덱스를 사용하지 않는다. 예를 들어, key_part1이 1과 100사이의
값을 고르게 가지고 있다면, 다음과 같은 쿼리에서 인덱스를 사용하는 것은 좋지 않다.
SELECT * FROM table_name where key_part1 > 1 and key_part1 < 90;
HEAP 테이블을 사용하고 있으며, 모든 키 부분들에 대해서 = 로 검색하지 않을 경우
HEAP 테이블에 대해 ORDER
BY 절로 쿼리할 경우
맨 처음의 키 부분을 사용하지 않을 경우
SELECT * FROM table_name WHERE key_part2 = 1;
와일드카드 문자로 시작하는 LIKE 를 사용할 경우
SELECT * FROM table_name WHERE key_part1 LIKE '%jani%'
하나의 인덱스에 대해서 검색하면서 다른 인덱스에 대해서는 ORDER BY 를 적용할 때
SELECT * FROM table_name WHERE key_part1 = # ORDER BY key2;
EXPLAIN 사용법 익히기
지나치게 느리다고 생각되는 모든 쿼리 문장에 대해 EXPLAIN 을 사용한다.
mysql> explain select t3.DateOfAction, t1.TransactionID
-> from t1
join t2 join t3
-> where t2.ID = t1.TransactionID and t3.ID =
t2.GroupID
-> order by t3.DateOfAction,
t1.TransactionID;
+-------+--------+---------------+---------+---------+------------------+------+---------------------------------+
|
table | type | possible_keys | key | key_len | ref | rows | Extra
|
+-------+--------+---------------+---------+---------+------------------+------+---------------------------------+
|
t1 | ALL | NULL | NULL | NULL | NULL | 11 | Using temporary; Using filesort
|
| t2 | ref | ID | ID | 4 | t1.TransactionID | 13 | |
| t3 | eq_ref |
PRIMARY | PRIMARY | 4 | t2.GroupID | 1 |
|
+-------+--------+---------------+---------+---------+------------------+------+---------------------------------+
유형 ALL과 범위는 잠재적인 문제점을 알리고 있다.
SHOW PROCESSLIST 사용법 익히기
현재 진행 상황을 파악하기 위해서는 SHOW processlist 를 사용한다.
+----+-------+-----------+----+---------+------+--------------+-------------------------------------+
|
Id | User | Host | db | Command | Time | State | Info
|
+----+-------+-----------+----+---------+------+--------------+-------------------------------------+
|
6 | monty | localhost | bp | Query | 15 | Sending data | select * from
station,station as s1 |
| 8 | monty | localhost | | Query | 0 | | show
processlist
|
+----+-------+-----------+----+---------+------+--------------+-------------------------------------+
mysql에서 KILL을 사용하거나 명령행에서 mysqladmin을 사용하여 불필요한(runaway) 쓰레드들을 없앨 수 있다.
MySQL이 쿼리를 해결하는 방법을 찾는 방법
다음 명령들을 실행해서 결과를 이해하도록 노력한다.
SHOW VARIABLES;
SHOW COLUMNS FROM ... \G
EXPLAIN SELECT ... \G
FLUSH STATUS;
SELECT ...;
SHOW STATUS;
MySQL은 이런 경우 극히 우수하다
로그 기록시
많은 연결이 이루어 질 때, 연결 속도가 매우 빠르다.
SELECT 와 INSERT 를 동시에 사용하는 곳에서.
update를 시간이 오래 걸리는 select 문과 결합하지 않을 때
대부분의 select/update 문이 고유한 키들을 사용할
때
많은 테이블을 장시간 잠금(lock) 충돌 없이 사용할 때
크기가 큰 테이블을 가지고 있을 때 (MySQL 은 매우 컴팩트한
테이블 포맷을 사용한다.)
MySQL 사용에 있어서 피해야 할 것들
테이블을 UPDATE 또는 삭제된 행을 테이블에 대해 INSERT하면서 시간이 오래 걸리는 SELECT 절들과 결합시키는 일
WHERE 절에 올 수 있는 것들에 대한 HAVING
키를 사용하지 않은, 또는 충분히 유니크하지 않은 키를 사용한 JOIN
컬럼 유형이 서로 다른 컬럼들에 대해 JOIN 수행
온전한 키 전체가 아닌 키의 부분에 대해서만 '=' 로 비교연산할 때 HEAP 테이블을 사용
MySQL monitor 에서 UPDATE 나 DELETE를 사용하면서 WHERE 절을 생략하는 일. 만약 자신이 이런 경향이 있다면,
mysql 클라이언트 프로그램을 실행할 때 --i-am-a-dummy 옵션을 추가하기 바란다.
MySQL의 독특한 잠금들(locks)
내장된 테이블 잠금
LOCK TABLES (모든 테이블 유형에 대해 동작함)
GET_LOCK() /
RELEASE_LOCK()
Page locks (BDB 테이블에 대해서)
ALTER TABLE 역시 BDB 테이블에 대해 테이블
잠금을 수행함
LOCK TABLES 는 다중 읽기 작업 또는 한개의 쓰기 작업을 허용한다.
보통 WRITE 잠금은 READ 잠금
보다 우선 순위가 높다. 쓰기 작업이 무한정 대기 상태에 놓이게 되는 경우를 피하기 위해서다(to avoid starving the
writers). 그리 중요하지 않은 쓰기 작업은 LOW_PRIORITY 키워드를 사용하여 lock handler가 읽기 작업에 먼저 허가를
내어 주도록 하는 것도 한 방법이다.
UPDATE LOW_PRIORITY SET value=10 WHERE id=10;
문제를 쉽게 해결하기 위해 MySQL로부터 더 많은 정보를 얻는 기법들
MySQL 만의 기능들을 항상 주석처리함으로써 쿼리의 이식성
높일 수 있다.
SELECT /*! SQL_BUFFER_RESULTS */ ...
SELECT SQL_BUFFER_RESULTS ...
MySQL이 임시 결과 세트를 만들도록 강제한다. 임시 세트가 만들어지면, 그
테이블들에 대한 모든 잠금이 해제된다. 이는 테이블 잠금으로 인해 문제가 발생했을 때나 쿼리 결과를 클라이언트로 전송하는데 오랜 시간이 소요되는
경우에 도움이 된다.
SELECT SQL_SMAIL_RESULT ... GROUP BY ...
결과 세트가 적은 수의 레코드만 가지게끔 하도록
옵티마이저에게 지시한다.
SELECT SQL_BIG_RESULT ... GROUP BY ...
결과 세트가 많은 수의 레코드를 가지도록 옵티마이저에게
지시한다.
SELECT STRAIGHT_JOIN ...
옵티마이저가 FROM 절에 나타난 순서대로 테이블을 join 하도록
강제한다.
SELECT ... FROM table_name [USE INDEX (index_list) | IGNORE INDEX
(index_list)] table_name2
MySQL이 특정 인덱스들을 사용하거나 무시하도록 강제한다.
트랜잭션 사용예
MyISAM 테이블에 대해 트랜잭션을 수행하는 방법:
mysql> LOCK TABLES trans READ, customer WRITE;
mysql> select
sum(value) from trans where customer_id=some_id;
mysql> update customer
set total_value=sum_from_previous_statement where
customer_id=some_id;
mysql> UNLOCK TABLES;
Berkeley DB 테이블에 대해 트랜잭션을 수행하는 방법:
mysql> BEGIN WORK;
mysql> select sum(value) from trans where
customer_id=some_id;
mysql> update customer set
total_value=sum_from_previous_statement where customer_id=some_id;
mysql>
COMMIT;
다음과 같이 함으로써 여러 트랜잭션들 간의 간섭을 방지할 수 있다는 점에 주목할 필요가 있다:
UPDATE customer SET value=value+new_value WHERE customer_id=some_id;
REPLACE 사용예
REPLACE는 테이블의 이전 레코드가 새 레코드와 같은 고유 인덱스 값을 가지고 있다면 예전 레코드가 먼저
삭제되고 새 레코드가 추가된다는 점만 제외하면 INSERT와 똑같이 작동한다.
다음과 같이 하는 대신,
SELECT 1 FROM t1 WHERE key=#
IF found-row
LOCK TABLES t1
DELETE FROM
t1 WHERE key1=#
INSERT INTO t1 VALUES (...)
UNLOCK TABLES t1;
ENDIF
다음과 같이 한다.
REPLACE INTO t1 VALUES (...)
일반적인 팁
프라이머리 키는 짧은 것을 사용한다. 테이블 조인할 때는 문자열형 보다는 숫치형을 사용한다.
여러 부분으로
구성된 키를 사용할 때는 첫 번째 부분이 가장 많이 사용되는 키이어야 한다.
의심스러울 때는, 앞부분이 더 많이 중복된 컬럼을 사용해서
보다 나은 키 압축 효과를 얻는다.
클라이언트를 실행 중이고 MySQL 서버가 같은 머신에 있다면, TCP/IP 대신에 유닉스 소켓을
사용하여 서버에 연결하는 것이 좋다.(이렇게 하면 7.5% 정도까지 효율이 증진된다.) MySQL 서버에 접속할 때 호스트이름이나
localhost를 지정하지 않으면 유닉스 소켓으로 접속하게 된다.
가능하다면 --skip-locking(일부 운영체제에서는 이 것이
기본값이다)을 사용한다. 이는 외부적인 잠금을 사용하지 않게 되고 퍼포먼스가 향상된다.
긴 키를 사용하기 보다는 응용프로그램 수준에서
해시된 값을 사용한다.
SELECT * FROM table_name WHERE hash=MD5(concat(col1,col2)) AND
col_1='constant' AND col_2='constant';
Store BLOB's that you need to access as files in files. 데이터베이스에는 파일이름만
저장한다.
레코드들의 큰 부분을 지우는 것 보다 레코드 전체를 지우는 것이 더 빠르다.
SQL이 충분히 빠르지 않다면, 데이터에
접근하는 더 낮은 수준의 인터페이스를 점검해 본다.
MySQL 3.23을 사용할 때 얻을 수 있는 이점
MyISAM; 이식이 수월한 거대 테이블 유형
HEAP; 메모리 상의
테이블
Berkeley DB; Sleepycat에서 제공하는 트랙잰션이 가능한 테이블
대폭 확대된(풀린) 제한들
동적
문자셋
더 많이 제공되는 STATUS 변수들
CHECK table, REPAIR table
더 빠른 GROUP BY 절과
DISTINCT 절
최적화된 LEFT JOIN ... IF NULL
CREATE TABLE ... SELECT
CREATE
TEMPORARY table_name (...)
임시적인 HEAP에서 MyISAM 테이블로의 자동 변환
리플리케이션
mysqlhotcopy 스크립트
실제 작업에서 중요한 기능들
진보된 트랜잭션
오류로부터 안전한 리플리케이션
텍스트 검색
많은 테이블의 삭제
(이 작업 후에 많은 테이블의 갱신이 이루어진다.)
너 나은 키 캐시
원자화된 RENAME (RENAME TABLE foo as
foo_old, foo_new as foo)
쿼리 캐시
MERGE TABLES
향상된 GUI 클라이언트
jQuery Core는 말 그대로 핵입니다. ^^; 다른 Library들은 다 이 걸
기반으로 작동하도록 만들어진거죠. 해당 사이트에 보시면 Reference나 Tutorial 등이 있으니 하나씩 따라해 보시면 jQuery 식의
프로그래밍에 대한 감을 잡으실 수 있을 겁니다. 이 것만 익혀서 적용하셔도 기존의 JavaScript 코드를 상당 부분 줄일 수 있습니다.
jQuery의 장점이 여러가지가 있지만 제가 제일 맘에 들어하는 건 DOM 구조를 다루는데 간편한 함수를 제공하고 속도가 빠르다는 점입니다.
그냥 HTML을 문자열로 만들어서 대상 태그 아래로 넣든지 교체하든지 앞에 넣든지 뒤에 넣든지 다 할 수 있습니다.
그리고 요즘
JavaScript Library들의 특징이 CSS 3 식의 Selector를 사용하게 하는 건데요. 이게 정말 강력합니다. 여기선 간단한 소개
내용이니 구체적인 건 설명하지 않겠습니다. 문서를 보세요. ^^
jQuery UI는 jQuery 에서 공식적으로 진행하고 있는
UI Library입니다. 현재는 기반이 되는 기능과 특수효과, 그리고, 가장 많이 사용할 것으로 여겨지는 Widget 들을 제공하고
있습니다.
그리고, 강력한 테마기능을 갖추고 있습니다. 다른 UI 플러그인 들이 이를 기반으로
작성하면 테마가 같이 적용됩니다. 테마는 이미 등록된 것을 사용할 수도 있구요. Theme Roller 에서 자신만의
테마를 정의할 수도 있는데, 기등록된 테마를 기반으로 할 수도 있습니다. 예제에 보면 동적으로 테마를 바꾸는 기능이 있는데요, Cookie 에
선택한 값을 저장하도록 되어 있어서 개인마다 취향대로 테마를 선택할 수도 있습니다.
이 Library가 기대가 많이 됩니다. Wiki
쪽에 보면 여러 Widget들이 개발중인 걸 보실 수 있습니다.
jQuery Grid는 말 그대로 Grid 기능입니다. 이번에
사용해 본 결과 상당히 만족스럽네요. Grid가 가져야할 기본 기능 외에도 Tree Grid 기능도 있고, Subgrid 기능도 갖추고
있습니다. Tree Grid 는 한 칼럼만 사용하면 그냥 간단한 Tree 처럼 사용할 수도 있습니다. 아쉬운 건 한국형 표에서 많이 나오는 다중
칼럼이 안 된다는 거요. ^^; 이건 그냥 출력용으로 HTML로 구현하면 될 듯.
이 Grid는 여기서 소개하기에는 너무 많은 기능을
자랑합니다. Grid 자체에서 새 항목을 등록하거나 수정하는 기능을 칼럼에 대한 설정만으로도 가능하게 되어 있습니다. 데모나 문서를 참조해서
보세요.
jQuery Form은 Form 값을 Ajax로 처리하는 걸 간편하게 해 주는 Library입니다. 처리의 간편함을
위해 사용했습니다. 아쉬운 건 JavaScript Object의 값을 Form의 각 요소에 세팅해 주는 게 있었으면 했는데 없어서 직접
구현했네요.
jquery keyfilter는 Input 필드나 TextArea에서 Key 입력을 제한해 주는
Library입니다. 보통 keydown 이벤트에 keyCode 값을 읽어 true / false를 돌려 주는 식으로 구현을 많이 하는데 역시
이걸 사용하면 간편해집니다.
jquery numberformatter 는 숫자 포매팅해 주는 Library 입니다. Locale
을 적용해서 포매팅 해 주는 게 특징이구요. 패턴을 직접 지정해 줄 수도 있습니다.
UI.Layout 은
BorderLayout을 구현한 건데요. Java에서 AWT, Swing 프로그램이나 델파이 같은 RAD 툴을 써 보신 분은 아실 겁니다.
화면의 영역은 east, west, south, north, center 5가지 영역으로 나누어 놓고, 전체 화면의 크기가 변경될 때 east,
west는 지정한 폭을, south, north 는 지정한 높이를 유지시켜 주는 역할을 합니다. 물론 그렇기 때문에 center 영역은 나머지
4개 영역을 제외한 영역으로 꽉 차게 유지가 되는 거죠.
여기에 동서남북 4개 영역과 center 사이의 경계를 드래그로 조절하게
한다든지 4개 영역을 닫았다 열었다 한다든지 하는 기능들이 들어 있습니다. 웹 프로그램이 Thin Client 역할로 사용되면서 이런 기능들이
요구되고 있는 상황인 거죠.
이 Layout 이 아쉬운 부분이 jQuery Grid와 연동이 자동으로 안 되고 onresize 이벤트
핸들러를 만들어 처리해 주어야 하는 점이었습니다. 하지만 복합한 코딩을 요구하는 건 아니니까요. 간단히 작성하실 수 있을
겁니다.
그리고 마지막 뽀너스입니다. ^^
이번 프로젝트에서 써 보지는 않았는데요. 설마 이런 게 JavaScript로
가능하리라고는 생각지 않아서 검색조차 안 해 봤는데 있더라구요. MaskEdit 가 있었습니다.
gamja : Web application simple validation checking script for webpage
Simple Validation check Scanner - with all perimeter [ XSS , Validation Error , SQL Injection ...]
gamja v.1.6 - from screammingCSS+ Paros+ Private skill
Requirements: wget , Perl
- p4ssion AT gmail.com . July 2005 GPL
----------------------------------------------------------------------------------------
Usage:
- For windows
Install ActivePerl : go www.activestate.com and download Active perl [Free download]
Unzip gamja.zip , Run c:\perl\perl gamja.pl "http://target[:port][/start/page] or c:\perl\gamja.pl "http://target[:port][/start/page]"
sit back and relax for result
Check html result : target-validation-bug.html
- For Linux
Unzip gamja.zip , Run /perl> gamja-l.pl "http://target/"
* open (sock, "/usr/bin/wget -U Mozilla -q -O - \"$url\"|"); - line 670 : change wget
sit back and relax for result
Check html result : target-validation-bug.html
Detail mode:
if you want to debug use -v option , gamja.pl -v http://host.name[:port][/start/page]
if you have any question send a email to p4ssion AT gmail.com
----------------------------------------------------------------------------------------
본 Perl script는 2005년에 작성된 파일입니다. [ 이후 조금씩 수정 되었습니다.]
악의적인 목적이 아닌 이상 자유롭게 수정을 하셔도 됩니다.
사용방법은 간단하며 gamja.pl "target host" 지정을 하시면 처리가 됩니다.
Web page내에 포함된 다수의 링크를 확인 하여 이후 연결 부분 및 서브페이지 까지 진단을 하여 일괄 진단이
가능하도록 되어 있습니다. 사이트 규모가 클 경우에는 진단 시간이 오래 걸릴 수 있습니다.
gamja.pl : For windows - Active Perl 이 설치 되어 있어야 하며 [ 당연히 Perl script 실행을 위해] 첨부된 Wget.exe
파일이 실행 디렉토리에 존재 하여야 합니다. 존재할 경우 실행 결과는 실행 디렉토리에 html 파일로 결과가 생성이 되며
각 URL의 인자마다 Validation check를 진행하여 문제가 있는 부분을 찾아내게 됩니다.
문제가 있는 부분에는 Type error 들도 찾아내도록 되어 있으며 Cross Site scripting 문제 및 SQL Injection 관련 문제들을
찾아낼 수 있도록 하였으나 부족한 부분들이 많이 있습니다.
기본적인 검수 여력이 없는 중소규모 사이트들에 사용이 되었으면 합니다.
-바다란 p4ssion AT gmail.com