<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>솔릿옵하의 블로그 &#187; MySQL</title>
	<atom:link href="http://www.onuyi.net/blog/archives/category/code/mysql-code/feed" rel="self" type="application/rss+xml" />
	<link>http://www.onuyi.net/blog</link>
	<description>당신은 나에게 충고를 할 자유가 있고 나는 그걸 듣지 않을 권리가 있다.</description>
	<lastBuildDate>Thu, 22 Dec 2011 13:07:58 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>자주 쓰는 MySQL 명령어 정리</title>
		<link>http://www.onuyi.net/blog/archives/118?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=%25ec%259e%2590%25ec%25a3%25bc-%25ec%2593%25b0%25eb%258a%2594-mysql-%25eb%25aa%2585%25eb%25a0%25b9%25ec%2596%25b4-%25ec%25a0%2595%25eb%25a6%25ac</link>
		<comments>http://www.onuyi.net/blog/archives/118#comments</comments>
		<pubDate>Wed, 05 Sep 2007 04:00:00 +0000</pubDate>
		<dc:creator>SOLID.H</dc:creator>
				<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[nero [http://moyiza.net]&#160; 정리
# root암호설정 &#8211; root로 로그인하여 해야함% mysqladmin -u root password &#8216;변경암호&#8217;%
mysqladmin -u root -p기존암호 password &#8216;변경암호&#8217;
root암호변경설정PLEASE
REMEMBER TO SET A PASSWORD FOR THE MySQL root USER !This is done
with:/usr/bin/mysqladmin -u root -p password
&#8216;new-password&#8217;/usr/bin/mysqladmin -u root -h ns.moyiza.net -p password
&#8216;new-password&#8217;
DB작업DB생성: mysql&#62; create database DB명 (
or % mysqladmin -u root -p create DB명 )DB삭제: mysql&#62; drop [...]
No related posts.]]></description>
			<content:encoded><![CDATA[<p>nero [<a href="http://moyiza.net" target="_blank">http://moyiza.net</a>]&nbsp; 정리<b></p>
<p># root암호설정 &#8211; root로 로그인하여 해야함</b><br />% mysqladmin -u root password &#8216;변경암호&#8217;<br />%<br />
mysqladmin -u root -p기존암호 password &#8216;변경암호&#8217;</p>
<p><b>root암호변경설정</b><br />PLEASE<br />
REMEMBER TO SET A PASSWORD FOR THE MySQL root USER !<br />This is done<br />
with:<br />/usr/bin/mysqladmin -u root -p password<br />
&#8216;new-password&#8217;<br />/usr/bin/mysqladmin -u root -h ns.moyiza.net -p password<br />
&#8216;new-password&#8217;</p>
<p><b>DB작업</b><br />DB생성: mysql&gt; create database DB명 (<br />
or % mysqladmin -u root -p create DB명 )<br />DB삭제: mysql&gt; drop database<br />
DB명<br />DB사용: mysql&gt; use DB명 (엄밀히 말하자면, 사용할 &#8216;default database&#8217;를 선택하는<br />
것이다.)<br />DB변경: mysql&gt; alter database db명 DEFAULT CHARACTER SET charset<br />
(4.1이상에서만 available)</p>
<p><b>MySQL 연결</b><br />mysql -u 사용자 -p DB명 ( or %<br />
mysqladmin -u root -p drop DB명 )</p>
<p><b>데이터파일<br />
실행(sql*loader기능)</b><br />mysql&gt;load data infile &#8220;데이터파일&#8221; into table 테이블명<br />
;<br />데이터파일에서 컬럼구분은 탭문자, Null값은 /n로 입력<br />데이터파일의 위치는 /home/kang/load.txt 와 같이<br />
절대경로로 지정할것.</p>
<p><b>질의 파일 실행</b><br />쉘프롬프트상에서<br />mysql -u 사용자 -p DB명 &lt;<br />
질의파일<br />or<br />mysql프롬프트상에서<br />mysql&gt; source 질의파일</p>
<p><b>쉘프롬프트상에서 질의<br />
실행</b><br />moyiza@nero board]$ mysql mysql -u root -pxxxx -e<br />
<br />&gt; &nbsp; &nbsp; &nbsp; &nbsp;&#8221;INSERT INTO db<br />
VALUES(<br />&gt; &nbsp; &nbsp; &nbsp; &nbsp;&#8217;localhost&#8217;,<br />
&#8216;aaa&#8217;, &#8216;aaa&#8217;,<br />&gt; &nbsp; &nbsp; &nbsp; &nbsp;&#8217;Y', &#8216;Y&#8217;,<br />
&#8216;Y&#8217;, &#8216;Y&#8217;, &#8216;Y&#8217;, &#8216;Y&#8217;, &#8216;Y&#8217;, &#8216;Y&#8217;, &#8216;Y&#8217;, &#8216;Y&#8217;)&#8221;</p>
<p><b>사용자 생성 &amp; 사용자에게<br />
DB할당</b><br />shell&gt; mysql &#8211;user=root -p mysql</p>
<p>mysql&gt; INSERT INTO<br />
user<br />
VALUES(&#8216;localhost&#8217;,'사용자&#8217;,PASSWORD(&#8216;비밀번호&#8217;),&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y');<br />mysql&gt;<br />
INSERT INTO user<br />
VALUES(&#8216;%&#8217;,'사용자&#8217;,PASSWORD(&#8216;비밀번호&#8217;),&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y');</p>
<p>mysql&gt;<br />
INSERT INTO<br />
db(Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv)<br />
VALUES (&#8216;localhost&#8217;,'DB명&#8217;,'사용자&#8217;,'Y&#8217;,'Y&#8217;,'Y&#8217;,'Y&#8217;,'Y&#8217;,'Y&#8217;);<br />mysql&gt; INSERT<br />
INTO<br />
db(Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv)<br />
VALUES(&#8216;%&#8217;,'DB명&#8217;,'사용자&#8217;,'Y&#8217;,'Y&#8217;,'Y&#8217;,'Y&#8217;,'Y&#8217;,'Y&#8217;);</p>
<p>mysql&gt; FLUSH<br />
PRIVILEGES; (or shell prompt: mysqladmin -u root -pxxxx reload)</p>
<p>CASE 2:<br />
GRANT명령을 이용한 사용자 생성(이 방법이 권장된다)<br />kang이라는 DB를 만들고, 이 DB를 아래에서 나열된 권한을 가진<br />
kang이라는 사용자를 생성<br />create database kang;<br />grant<br />
SELECT,INSERT,UPDATE,DELETE,CREATE,DROP on kang.* to <a href="mailto:kang@localhost">kang@localhost</a> identified<br />
by &#8216;kang&#8217;;<br />grant SELECT,INSERT,UPDATE,DELETE,CREATE,DROP on kang.* to<br />
kang@&#8217;%&#8217; identified by &#8216;kang&#8217;;</p>
<p>mysql&gt; create database kang;<br />Query<br />
OK, 1 row affected (0.00 sec)</p>
<p>mysql&gt; grant<br />
SELECT,INSERT,UPDATE,DELETE,CREATE,DROP on kang.* to <a href="mailto:kang@localhost">kang@localhost</a> identified<br />
by &#8216;kang&#8217;;<br />Query OK, 0 rows affected (0.00 sec)</p>
<p>mysql&gt; grant<br />
SELECT,INSERT,UPDATE,DELETE,CREATE,DROP on kang.* to kang@&#8217;%&#8217; identified by<br />
&#8216;kang&#8217;;<br />Query OK, 0 rows affected (0.01 sec)</p>
<p>mysql&gt;</p>
<p><b>여러가지<br />
명령정리</b><br />mysql&gt; show<br />
variables; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
서버의 variables(설정사항)출력<br />mysql&gt; show variables like<br />
&#8216;have_inno%&#8217; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
조건에 맞는 variables만 출력<br />mysql&gt; show<br />
databases; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
database목록<br />mysql&gt; show<br />
tables; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
현재DB의 테이블목록(temporary table은 출력하지 않음)<br />mysql&gt; show tables from<br />
db명; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;지정된<br />
db명이 소유한 테이블목록<br />mysql&gt; show tables like<br />
&#8216;mem%&#8217;; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
조건에 맞는 테이블목록만 출력<br />mysql&gt; show index from<br />
테이블명; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;인덱스<br />
보기<br />mysql&gt; show columns from<br />
테이블명; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
테이블구조(describe 테이블명, explain 테이블명)<br />mysql&gt; show table<br />
status; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
현재 DB의 테이블들의 상태(row수,table type,row길이,..)<br />mysql&gt; show table status from<br />
db명; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;지정된<br />
DB의 테이블들의 상태(row수,table type,row길이,..)<br />mysql&gt; show create table<br />
테이블명; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
해당 테이블 생성 SQL문 출력<br />mysql&gt; rename table 테이블1 to<br />
테이블2; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
테이블명 변경(ALTER TABLE 테이블1 RENAME TO 테이블2)<br />mysql&gt; rename table 테이블1 to 테이블2,<br />
테이블3 to 테이블4; &nbsp; &nbsp; &nbsp;rename multiple<br />
tables<br />mysql&gt; rename table db1명.테이블명 to<br />
db2명.테이블명; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;테이블을 다른<br />
DB로 이동<br />mysql&gt; alter table 테이블명 add 컬럼명<br />
데이터타입; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;컬럼추가<br />mysql&gt;<br />
alter table 테이블명 del<br />
컬럼명; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
컬럼제거<br />mysql&gt; alter table 테이블명 modify 컬럼명<br />
컬럼타입; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 컬럼명에 지정된 컬럼타입의<br />
변경<br />mysql&gt; alter table 테이블명 change old컬럼명 new컬럼명 컬럼타입 &nbsp; 컬럼명<br />
변경<br />mysql&gt; alter table 테이블명<br />
type=innodb; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
테이블type변경<br />mysql&gt; create table 테이블명(..) type=heap<br />
min_rows=10000; &nbsp; &nbsp; &nbsp; 10000row를 수용할 수 있을 만큼<br />
메모리할당(heap type이므로)<br />mysql&gt; select<br />
version(); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
MySQL서버버전 출력<br />mysql&gt; create table 테이블2 as select * from<br />
테이블1; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;테이블1과 동일한 테이블<br />
생성(with 데이터, as는 생략가능)<br />mysql&gt; create table 테이블2 as select * from 테이블1<br />
where 1=2; &nbsp; 테이블1과 동일한 구조의 테이블 생성(without 데이터, 1=2는 0으로 할수도<br />
있다.)<br />mysql&gt; insert into 테이블2 select * from<br />
테이블1; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
테이블1의 데이터를 테이블2에 insert</p>
<p><b>테이블이 존재여부 파악</b><br />DROP TABLE IF EXISTS<br />
테이블명;<br />CREATE TABLE 테이블명 (&#8230;);<br />프로그래밍 언어에서 COUNT(*)를 사용하여 질의가 성공하면 테이블이<br />
존재함을 파악할 수 있다.<br />ISAM, MyISAM의 경우 COUNT(*)가 최적화되어 상관없으나, BDB, InnoDB의 경우 full<br />
scan이 발생하므로 사용하지 마라.<br />대신 select * from 테이블명 where 0; 을 사용하라. 질의가 성공하면 테이블이<br />
존재하는 것이고, 아니면 존재하지 않는 것이다.</p>
<p><b>접속</b><br />mysql {-h 접속호스트} -u 사용자<br />
-p 사용DB<br />-h로 다른 서버에 존재하는 MySQL접속시 다음과 같이 MySQL DB에 설정해줘야 한다.<br />mysql&gt;<br />
INSERT INTO user VALUES(&#8216;접근을 허용할<br />
호스트ip&#8217;,'사용자&#8217;,PASSWORD(&#8216;비밀번호&#8217;),&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y',&#8217;Y');<br />mysql&gt;<br />
INSERT INTO<br />
db(Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv)<br />
VALUES(&#8216;접근을 허용할 호스트ip&#8217;,'사용DB&#8217;,'사용자&#8217;,'Y&#8217;,'Y&#8217;,'Y&#8217;,'Y&#8217;,'Y&#8217;,'Y&#8217;);<br />mysql&gt; FLUSH<br />
PRIVILEGES; or 쉴프롬프트상에서 % mysqladmin -u root -p<br />
flush-privileges</p>
<p>검색조건(where)<br />regular expression을 지원하다니<br />
신기하군..<br />mysql&gt; select * from work where 열명 regexp &#8220;정규표현식&#8221;;</p>
<p><b>백업<br />
&amp; 복구</b><br />mysqldump {-h 호스트} -u 사용자 -p DB명 &gt; 백업파일<br />mysql {-h 호스트} -u<br />
사용자 -p DB명 &lt; 백업파일</p>
<p>mysqldump -u root -p &#8211;opt db_moyiza &gt;<br />
moyiza.sql<br />mysqldump -u root -p &#8211;opt db_board | mysql &#8212;host=remote-host<br />
-C database (상이한 머쉰)<br />mysql -u moyiza -p db_moyiza &lt;<br />
moyiza.sql</p>
<p>mysqldump -u root -p &#8211;opt db_moyiza | mysql<br />
&#8212;host=ns.moyiza.net -C db_moyiza</p>
<p>테이블 생성구문만을 화면에서 보려면 다음과 같이<br />
&#8211;no-data를 사용한다. 테이블명을 생략하면 모든 테이블 출력<br />mysqldump -u 유저명 -p &#8211;no-data db명<br />
테이블명</p>
<p><b>테이블 검사</b><br />isamchk</p>
<p>오라클 sysdate와 동일<br />insert into test<br />
values(&#8217;12&#8242;, now());</p>
<p>유닉스 time()함수 리턴값<br />
사용<br />FROM_UNIXTIME(954788684)<br />UNIX_TIMESTAMP(&#8220;2001-04-04<br />
:04:04:04&#8243;)</p>
<p><b>MySQL 디폴트 DB&amp;로그파일<br />
위치</b><br />/var/lib/mysql<br />/var/lib디렉토리는 여러 프로세스들이 사용하는 데이터를 저장하는 일종의 파일시스템상의<br />
데이터베이스라고 볼 수 있다.</p>
<p><b>replace</b><br />해당 레코드 존재하면 update하고, 존재하지 않는다면<br />
insert한다.(insert문법과 동일)<br />replace into test values(&#8216;maddog&#8217;,'kang myung<br />
gyu&#8217;)&#8217;</p>
<p><b>explain</b><br />explain 질의문: 지정한 질의문이 어떻게 실행될 건지를<br />
보여줌<br />mysql&gt; explain select u.uid, u.name, a.name from sm_user u, sm_addr a<br />
where<br />
u.uid=a.uid;<br />+&#8212;&#8212;-+&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;+&#8212;&#8212;-+&#8212;&#8212;+&#8212;&#8212;-+<br />|<br />
table | type | possible_keys &nbsp;|<br />
key &nbsp; &nbsp; &nbsp; &nbsp; | key_len | ref &nbsp;|<br />
rows | Extra<br />
|<br />+&#8212;&#8212;-+&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;+&#8212;&#8212;-+&#8212;&#8212;+&#8212;&#8212;-+<br />|<br />
u &nbsp; | ALL | PRIMARY &nbsp; &nbsp; &nbsp;|<br />
NULL &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; NULL | NULL |<br />
370 | &nbsp; &nbsp; |<br />| a &nbsp; | ref | sm_addr_uid_idx |<br />
sm_addr_uid_idx | &nbsp; &nbsp;11 | u.uid | &nbsp;11<br />
| &nbsp; &nbsp;<br />
|<br />+&#8212;&#8212;-+&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;+&#8212;&#8212;-+&#8212;&#8212;+&#8212;&#8212;-+<br />2<br />
rows in set (0.01 sec)</p>
<p><b>temporary table</b><br />크기가 큰 테이블에 있는<br />
subset에 대한 질의라면 subset을 temporary table에 저장한 후 질의하는 것이 더 빠를 경우가 있다.<br />temporary<br />
table는 세션내에서만 유효하고(현재 사용자만이 볼수 있다는 뜻), 세션종료시 자동적으로 drop된다.</p>
<p>create<br />
temporary table (&#8230;);<br />create temporary table (&#8230;)<br />
type=heap; &nbsp; &nbsp; 디스크가 아닌 메모리에 테이블 생성</p>
<p>존재하는 permanent<br />
table의 테이블명과 동일하게 생성할 수 있으며,<br />temporary table은 permanent table보다 우선시되어<br />
처리된다.<br />4.0.7의 감마버전에서 테스트하면 결과는 약간 달라진다. 버그인건지..</p>
<p>mysql&gt; create table<br />
test (id varchar(10));<br />Query OK, 0 rows affected (0.01 sec)</p>
<p>mysql&gt;<br />
insert into test values(&#8216;moyiza&#8217;);<br />Query OK, 1 row affected (0.00<br />
sec)</p>
<p>mysql&gt; create temporary table test(id varchar(10));<br />Query OK,<br />
0 rows affected (0.00 sec)</p>
<p>mysql&gt; select * from test;<br />Empty set<br />
(0.00 sec)</p>
<p>mysql&gt; drop table test;<br />Query OK, 0 rows affected (0.00<br />
sec)</p>
<p>mysql&gt; select * from test;<br />+&#8212;&#8212;&#8212;-+<br />|<br />
id &nbsp; &nbsp; |<br />+&#8212;&#8212;&#8212;-+<br />| moyiza<br />
|<br />+&#8212;&#8212;&#8212;-+<br />1 row in set (0.00 sec)</p>
<p><b>Table Type에 다른<br />
Files on Disk</b></p>
<p>ISAM &nbsp;.frm (definition) .ISD (data) .ISM<br />
(indexes)<br />MyISAM .frm (definition) .MYD (data) .MYI (indexes)<br />MERGE .frm<br />
(definition) .MRG (list of constituent MyISAM table<br />
names)<br />HEAP &nbsp;.frm (definition)<br />BDB &nbsp; .frm (definition)<br />
.db (data and indexes)<br />InnoDB .frm (definition)</p>
<p>보통 mysqldump를 사용하여 백업을<br />
수행하여 다른 DB서버에 데이터를 restore하면 된다.<br />MySQL은 별다른 작업없이 데이터파일을 단순히 복사(copy)하는 것만으로도<br />
다른 서버에<br />DB을 이동시킬 수 있다. 하지만, 이런 방식이 지원되지 않는 table type도 있다.</p>
<p>ISAM:<br />
machine-dependent format하기때문에..<br />BDB : .db파일에 이미 테이블위치가 encode되어<br />
있기때문에..<br />MyISAM, InnoDB, MERGE :가능(machine-independent format)</p>
<p>별다른 지정을<br />
하지 않았다면 디폴트 TABLE type이 MyISAM이므로, 무난히 migration할 수<br />
있다.<br />floating-point컬럼(FLOAT,DOUBLE)이 있다면 이러한 방식이 실패할 수 도 있다.</p>
<p>쉘에서는<br />
mysql이 되는데 PHP에서 mysql.sock error를 내면서 MySQL이 안되는 경우<br />mysql.sock은 /tmp 아니면<br />
/var/lib/mysql에 생기게 된다.<br />나의 경우, /var/lib/mysql에 mysql.sock파일이 있는데 PHP에서는<br />
/tmp에서 찾으려하면서 에러를 발생했다.<br />/usr/bin/safe_mysqld파일에서 다음과 같이 수정한다.<br />주석(#)이 달린 것이<br />
원래것이고 그 밑에 있는것이 수정한 것이다.</p>
<p>#<br />
MYSQL_UNIX_PORT=${MYSQL_UNIX_PORT:-/var/lib/mysql/mysql.sock}<br />MYSQL_UNIX_PORT=${MYSQL_UNIX_PORT:-/tmp/mysql.sock}</p>
<p>위와<br />
같이 하니 /usr/bin/mysql이 /var/lib/mysql/mysql.sock에서 소켓파일을 찾으려 했다.<br />socket file을<br />
지정하는 &#8211;socket이라는 옵션으로 다음과 같이 지정하면 된다.</p>
<p>mysql &#8211;socket=/tmp/mysql.sock -u<br />
moyiza -p db_test</p>
<p>하지만 mysql실행시마다 이렇게 써줘야한다는 것이 상당히 귀찮다. 옵션이 바로 적용되게<br />
설정하자.<br />mysql은 설정사항을 다음 3가지 파일에서<br />
검색한다.</p>
<p>/etc/my.cnf &nbsp; &nbsp; &nbsp; &nbsp;global<br />
options(MySQL 전체적으로 사용되는 옵션 정의)<br />mysql-data-dir/my.cnf 특정 DB에 적용되는 option<br />
(/var/lib/mysql/my.cnf)<br />~/.my.cnf &nbsp; &nbsp; &nbsp; &nbsp;<br />
사용자 각각의 설정(&#8216;~&#8217;문자는 사용자의 홈디렉토리는 의미)</p>
<p>/usr/share/mysql디렉토리에 예제가 있으므로<br />
참고한다.<br />소켓파일의 지정은 다음줄을 넣어주면<br />
된다.</p>
<p>socket &nbsp; &nbsp; &nbsp; =<br />
/tmp/mysql.sock</p>
<p>== /etc/my.cnf예 ==<br /># The following options will be<br />
passed to all MySQL clients<br />[client]<br />#password &nbsp; &nbsp; =<br />
your_password<br />port &nbsp; &nbsp; &nbsp; &nbsp;=<br />
3306<br />socket &nbsp; &nbsp; &nbsp; = /tmp/mysql.sock</p>
<p>#<br />
Here follows entries for some specific programs</p>
<p># The MySQL<br />
server<br />[mysqld]<br />port &nbsp; &nbsp; &nbsp; &nbsp;=<br />
3306<br />socket &nbsp; &nbsp; &nbsp; =<br />
/tmp/mysql.sock</p>
<p><b>MySQL에서 통계처리시</b><br />orderby, groupby 는<br />
sort_buffer를 늘여준다.(show variables)</p>
<p>live table(smslog)에서 모든 질의를 처리하지 말고<br />
summary table에 질의결과를 저장해 재질의 처리한다.<br />summary table이 heap-type table가 가능한지 확인할<br />
것.</p>
<p>INSERT INTO tblTemp2 (fldID) SELECT tblTemp1.fldOrder_ID FROM tblTemp1<br />
WHERE<br />&nbsp;&nbsp; tblTemp1.fldOrder_ID &gt; 100;</p>
<p>join이<br />
subselect보다 빠르다.<br />join시 사용되는 컬럼은 동일한 column type과 길이를 가져야만 최적의 속도를 보장한다.<br />즉,<br />
동일 column type이지만 길이가 다르다면(char(11), char(10)), 동일한 컬럼도메인으로 변경해주는 것이<br />
좋다.<br />where의 in은 optimize되어 있으므로 빠르다<br />insert,select는 동시에<br />
수행가능하다.(어떻게?)<br />explain으로 질의과정 점검</p>
<p><b>varchar to/from<br />
char</b><br />conversion varchar를 char로 변경할 경우 모든 컬럼타입을 동시에 변경해야 한다.<br />반대의 경우,<br />
하나만 char-&gt;charchar변경시 다른 모든 컬럼도 varchar로 변경됨<br />참.. 특이하구만..</p>
<p>mysql&gt;<br />
CREATE TABLE chartbl (name VARCHAR(40), address VARCHAR(80));<br />Query OK, 0<br />
rows affected (0.05 sec)</p>
<p>mysql&gt; desc<br />
chartbl;<br />+&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;+&#8212;&#8211;+&#8212;&#8212;&#8212;+&#8212;&#8212;-+<br />|<br />
Field &nbsp;| Type &nbsp; &nbsp; | Null | Key | Default | Extra<br />
|<br />+&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;+&#8212;&#8211;+&#8212;&#8212;&#8212;+&#8212;&#8212;-+<br />|<br />
name &nbsp; | varchar(40) | YES | &nbsp; | NULL &nbsp;<br />
| &nbsp; &nbsp; |<br />| address | varchar(80) | YES | &nbsp; |<br />
NULL &nbsp; | &nbsp; &nbsp;<br />
|<br />+&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;+&#8212;&#8211;+&#8212;&#8212;&#8212;+&#8212;&#8212;-+<br />2 rows in set<br />
(0.03 sec)</p>
<p>mysql&gt; alter table chartbl modify name char(40);<br />Query<br />
OK, 0 rows affected (0.02 sec)<br />Records: 0 Duplicates: 0 Warnings:<br />
0</p>
<p>mysql&gt; desc<br />
chartbl;<br />+&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;+&#8212;&#8211;+&#8212;&#8212;&#8212;+&#8212;&#8212;-+<br />|<br />
Field &nbsp;| Type &nbsp; &nbsp; | Null | Key | Default | Extra<br />
|<br />+&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;+&#8212;&#8211;+&#8212;&#8212;&#8212;+&#8212;&#8212;-+<br />|<br />
name &nbsp; | varchar(40) | YES | &nbsp; | NULL &nbsp;<br />
| &nbsp; &nbsp; |<br />| address | varchar(80) | YES | &nbsp; |<br />
NULL &nbsp; | &nbsp; &nbsp;<br />
|<br />+&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;+&#8212;&#8211;+&#8212;&#8212;&#8212;+&#8212;&#8212;-+<br />2 rows in set<br />
(0.00 sec)</p>
<p>mysql&gt; alter table chartbl modify name char(40), modify<br />
address char(80);<br />Query OK, 0 rows affected (0.01 sec)<br />Records: 0<br />
Duplicates: 0 Warnings: 0</p>
<p>mysql&gt; desc<br />
chartbl;<br />+&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;-+&#8212;&#8212;+&#8212;&#8211;+&#8212;&#8212;&#8212;+&#8212;&#8212;-+<br />|<br />
Field &nbsp;| Type &nbsp; | Null | Key | Default | Extra<br />
|<br />+&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;-+&#8212;&#8212;+&#8212;&#8211;+&#8212;&#8212;&#8212;+&#8212;&#8212;-+<br />| name &nbsp;<br />
| char(40) | YES | &nbsp; | NULL &nbsp; | &nbsp; &nbsp;<br />
|<br />| address | char(80) | YES | &nbsp; | NULL &nbsp;<br />
| &nbsp; &nbsp;<br />
|<br />+&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;-+&#8212;&#8212;+&#8212;&#8211;+&#8212;&#8212;&#8212;+&#8212;&#8212;-+<br />2 rows in set<br />
(0.00 sec)</p>
<p>mysql&gt;</p>
<p>&#8220;For each article, find the dealer(s)<br />
with the most expensive price.&#8221;</p>
<p>표준안<br />&nbsp;&nbsp; SELECT article,<br />
dealer, price<br />&nbsp;&nbsp; FROM &nbsp;shop s1<br />&nbsp;&nbsp; WHERE<br />
price=(SELECT<br />
MAX(s2.price)<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<br />
FROM shop<br />
s2<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<br />
WHERE s1.article = s2.article);</p>
<p>수정안(최적화)<br />&nbsp;&nbsp; CREATE TEMPORARY<br />
TABLE tmp (<br />&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; article INT(4)<br />
UNSIGNED ZEROFILL DEFAULT &#8217;0000&#8242; NOT<br />
NULL,<br />&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<br />
price &nbsp;DOUBLE(16,2) &nbsp; &nbsp; &nbsp; &nbsp;<br />
DEFAULT &#8217;0.00&#8242; NOT NULL);</p>
<p>&nbsp;&nbsp; LOCK TABLES shop<br />
read;</p>
<p>&nbsp;&nbsp; INSERT INTO tmp SELECT article, MAX(price) FROM shop<br />
GROUP BY article;</p>
<p>&nbsp;&nbsp; SELECT shop.article, dealer, shop.price<br />
FROM shop, tmp<br />&nbsp;&nbsp; WHERE shop.article=tmp.article AND<br />
shop.price=tmp.price;</p>
<p>&nbsp;&nbsp; UNLOCK TABLES;</p>
<p>&nbsp;&nbsp;<br />
DROP TABLE<br />
tmp;</p>
<p>========================================================<br /><b>MySQL<br />
특성정리</b><br />========================================================<br />primary<br />
key, foreign key지원<br />index 지원(15개컬럼, 256byte까지)<br />MySQL에서의 Stored Script개념<br />
=&gt; SQL server language<br />commit-rollback개념 =&gt; lock tables(lock table test<br />
write -&gt; 트랜잭션.. -&gt; unlock tables)<br />컬럼명길이: 64자까지, 컬럼 Alias: 256자까지<br />not<br />
case-sensitive: keywords, functions, column, index명<br />case-sensitive: database,<br />
table, alias명<br />키워드,함수명은 대소문자구별이 없지만, db명과 table명은 Unix계열이라면<br />
case-sensitive하다.<br />(이는 오브젝트명이 OS의 fs에 따라 저장되기 때문이다. 서버의 lower_case_table_names<br />
변수를<br />1로 설정하면 오브젝트명은 모두 소문자로 저장되므로 유닉스-윈도간 호환성을 높일 수 있다.</p>
<p>지원되지 않는 부분:<br />
<br />Stored Procedure(5.0이상부터 지원된다고 함)<br />View(5.0이상부터 지원된다고<br />
함)<br />Trigger(5.0이상부터 지원된다고 함)<br />subquery(4.1이상부터 지원된다고 함)<br />union, union<br />
all(4.0이상부터 지원됨)</p>
<p><b>[테이블 type에 따른 인덱스 특성]</b><br />Index<br />
Characteristic &nbsp; &nbsp; &nbsp; &nbsp;ISAM &nbsp;<br />
MyISAM &nbsp; &nbsp; &nbsp; &nbsp;<br />
HEAP &nbsp; &nbsp;<br />
BDB &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; InnoDB<br />NULL<br />
values allowed &nbsp; &nbsp; &nbsp; &nbsp;<br />
No &nbsp; &nbsp;Yes &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
As of 4.0.2 Yes &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
Yes<br />Columns per<br />
index &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;16 &nbsp; &nbsp;16 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;16 &nbsp; &nbsp; &nbsp;<br />
16 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;16<br />Indexes<br />
per<br />
table &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;16 &nbsp; &nbsp;32 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;32 &nbsp; &nbsp; &nbsp;<br />
31 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;32<br />Maximum<br />
index row size (bytes) 256 &nbsp;<br />
500 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
500 &nbsp; &nbsp; &nbsp;500/1024 &nbsp; &nbsp; &nbsp; &nbsp;500/1024<br />Index<br />
column prefixes allowed &nbsp;Yes &nbsp;<br />
Yes &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
Yes &nbsp; &nbsp; &nbsp;Yes &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
No<br />BLOB/TEXT indexes allowed &nbsp; &nbsp;<br />
No &nbsp; &nbsp;Yes(255 bytes max)<br />
No &nbsp; &nbsp; &nbsp; Yes (255 bytes max) No</p>
<p><b>인덱스<br />
생성</b><br />- alter table을 이용한 인덱스 생성이 더 flexible함<br />- 인덱스명은 생략가능</p>
<p>ALTER<br />
TABLE 테이블명 ADD INDEX 인덱스명 (인덱스컬럼);<br />ALTER TABLE 테이블명 ADD UNIQUE 인덱스명<br />
(인덱스컬럼);<br />ALTER TABLE 테이블명 ADD PRIMARY KEY (인덱스컬럼);<br />ALTER TABLE 테이블명 ADD<br />
FULLTEXT (인덱스컬럼);</p>
<p>CREATE INDEX 인덱스명 ON 테이블명 (인덱스컬럼);<br />CREATE UNIQUE<br />
INDEX 인덱스명 ON 테이블명 (인덱스컬럼);<br />CREATE FULLTEXT INDEX 인덱스명 ON 테이블명<br />
(인덱스컬럼);</p>
<p>unique인덱스와 primary key인덱스와의 차이<br />unique은 null허용하지만, primary<br />
key는 null허용 안함<br />unique은 하나의 테이블에 여러개 올 수 있지만, primary key는 하나만<br />
존재</p>
<p><b>테이블생성시 지정</b><br />CREATE TABLE 테이블명<br />(<br />&#8230; column declarations<br />
&#8230;<br />INDEX 인덱스명 (인덱스컬럼),<br />UNIQUE 인덱스명 (인덱스컬럼),<br />PRIMARY KEY<br />
(인덱스컬럼),<br />FULLTEXT 인덱스명 (인덱스컬럼),<br />&#8230;</p>
<p>);</p>
<p><b>index prefix<br />
생성</b><br />- 컬럼의 전체길이중 일부만 인덱스로 사용<br />- supported for ISAM, MyISAM, HEAP, and BDB<br />
tables, but not for InnoDB tables<br />- 지정되는 길이는 byte단위가 아닌 charater단위이므로,<br />
multi-byte character일 경우 주의<br />- blob, text 컬럼타입일 경우, index prefix 가 유용(255 길이까지<br />
가능)</p>
<p>CREATE TABLE 테이블명<br />(<br />name CHAR(30) NOT NULL,<br />address CHAR(60)<br />
NOT NULL,<br />INDEX (name(10),address(10))<br />);</p>
<p><b>인덱스 삭제</b><br />DROP<br />
INDEX 인덱스명 ON 테이블명;<br />ALTER TABLE 테이블명 DROP INDEX 인덱스명;<br />ALTER TABLE 테이블명<br />
DROP PRIMARY KEY;</p>
<p><b>outer join</b> </p>
<p>[MySQL] <br />left outer<br />
joing : SELECT t1.*, t2.* FROM t1 LEFT OUTER JOIN t2 ON t1.i1 = t2.i2;<br />right<br />
outer joing: SELECT t1.*, t2.* FROM t1 RIGHT OUTER JOIN t2 ON t1.i1 =<br />
t2.i2;</p>
<p>[Oracle]<br />left outer joing : SELECT t1.*, t2.* FROM t1, t2 where<br />
t1.i1 = t2.i2(+);<br />right outer joing: SELECT t1.*, t2.* FROM t1, t2 where<br />
t1.i1(+) = t2.i2;</p>
<p>SELECT<br />student.name,<br />
student.student_id,<br />event.date, event.event_id,<br />
event.type<br />FROM<br />student, event<br />LEFT JOIN score ON student.student_id =<br />
score.student_id<br />&nbsp; &nbsp; &nbsp;&nbsp; AND event.event_id =<br />
score.event_id<br />WHERE<br />score.score IS NULL<br />ORDER<br />
BY<br />student.student_id, event.event_id;</p>
<p><b>:= 문장을 이용한 변수의<br />
설정</b></p>
<p>현재 moyiza의 데이터베이스강좌게시판에 등록된 총 게시물은 43개이다. 43개의 강좌를 읽은 수(hit수)는<br />
각각 다르다.<br />평균 hit수를 구해 보자.</p>
<p>mysql&gt; select @total_hit := sum(hit),<br />
@total_record := count(*) from<br />
zetyx_board_database;<br />+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+<br />|<br />
@total_hit := sum(hit) | @total_record := count(*)<br />
|<br />+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+<br />| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
3705<br />
| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;43<br />
|<br />+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+<br />1 row in set<br />
(0.00 sec)</p>
<p>mysql&gt; select @total_hit/@total_record as<br />
평균HIT;<br />+&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+<br />|<br />
평균HIT &nbsp; &nbsp; &nbsp;|<br />+&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+<br />|<br />
86.162790697674 |<br />+&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+<br />1 row in set (0.00<br />
sec)</p>
<p>select substring(subject from 9) from zetyx_board_database<br />
where substring(subject, 1, <img src='http://www.onuyi.net/blog/wp-includes/images/smilies/icon_cool.gif' alt='8)' class='wp-smiley' /> = &#8216;[ORACLE]&#8216;;</p>
<p>보통 상용DBMS들이 row-level<br />
locking을 지원한다. 쉽게 말해 레코드단위로 락킹한다는 말이다.<br />반면, MySQL의 MyISAM 테이블타입은 table-level<br />
locking을 사용한다. <br />쉽게 말하면, insert, update, delete작업은 전체 테이블에 락을 걸고 처리된다는<br />
것이다.<br />row-level락보다 비효율적이지만,.. MySQL은 빠르기 때문에 이 단점이 상쇄된다.</p>
<p><b>Compressed<br />
MyISAM(packed MyISAM)</b><br />정적인 테이블데이터는 압축하여 20-60%정도의 공간을 절약할 수<br />
있다.<br />Production데이터를 CD로 받아서 차후 디스크에 풀지 않고 CD자체로 바로 사용할 수도 있다.<br />gzip등으로 백업받으면<br />
이를 푸는 과정이 필요할 것이다.<br />% myisampack moyiza.myi</p>
<p>데이터베이스 게시판의 Merge Table에<br />
좀 더 자세한 내용을 적어 두었다.</p>
<p><b>RAID Table</b><br />1개의 테이블은 OS상에 3개의 파일로<br />
구성된다.<br />스키마파일(.frm), data파일(.myd), index파일(.myi)<br />MySQL의 RAID테이블은<br />
데이터파일(.myd)을 여러개의 파일들로 구성하는 것이다.</p>
<p>create table raid_test<br />
(&#8230;)<br />type=myisam raid_type=striped raid_chunks=4 raid_chunsize=8</p>
<p>테이블을<br />
4개의 데이터파일로 나누고, 8kb단위로(8kb stripe) 라운드로빈 방식으로 write가 이루어진다. </p>
<p>This article<br />
comes from moyiza.net (Leave this line as is)</p>
<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://www.onuyi.net/blog/archives/118/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>25가지 SQL작성법</title>
		<link>http://www.onuyi.net/blog/archives/117?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=25%25ea%25b0%2580%25ec%25a7%2580-sql%25ec%259e%2591%25ec%2584%25b1%25eb%25b2%2595</link>
		<comments>http://www.onuyi.net/blog/archives/117#comments</comments>
		<pubDate>Wed, 05 Sep 2007 03:00:00 +0000</pubDate>
		<dc:creator>SOLID.H</dc:creator>
				<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[출처:phpschool
1.데이터와 비즈니스 어플리케이션을 잘 알아야 한다. 
동일한 정보는 다른 비즈니스 데이터 원천으로부터 검색될 수 있다. 이러한 원천에 익숙해야 한다. 
당신은 당신의 데이터베이스 안의 데이터의 크기와 분포를 반드시 알아야 한다. 
또한 SQL을 작성하기 전에 비즈니스 개체 안의 관계와 같은 데이터 모델을 전체적으로 이해해야 
한다. 이러한 이해는 당신이 여러 테이블에서 정보를 검색하는데 있어서 보다 좋은 쿼리를 작성할 [...]
No related posts.]]></description>
			<content:encoded><![CDATA[<p>출처:phpschool</p>
<p>1.데이터와 비즈니스 어플리케이션을 잘 알아야 한다. <br />
동일한 정보는 다른 비즈니스 데이터 원천으로부터 검색될 수 있다. 이러한 원천에 익숙해야 한다. <br />
당신은 당신의 데이터베이스 안의 데이터의 크기와 분포를 반드시 알아야 한다. <br />
또한 SQL을 작성하기 전에 비즈니스 개체 안의 관계와 같은 데이터 모델을 전체적으로 이해해야 <br />
한다. 이러한 이해는 당신이 여러 테이블에서 정보를 검색하는데 있어서 보다 좋은 쿼리를 작성할 <br />
수 있다. DESIGNER/2000과 같은 CASE TOOLS은 다른 비즈니스와 데이터베이스 객체사이의 관계 <br />
를 문서화 하는데 좋은 역할을 한다. </p>
<p>2.실제 데이터를 가지고 당신의 쿼리를 검사하라. <br />
대부분의 조직은 개발, 검사, 제품의 3가지 데이터베이스 환경을 가진다. 프로그래머는 <br />
어플리케이션을 만들고 검사하는데 개발 데이터베이스 환경을 사용하는데, 이 어플리케이션이 <br />
제품 환경으로 전환되기 전에 프로그래머와 사용자에 의해 검사 환경하에서 보다 엄격하게 검토되어 <br />
야 한다. <br />
SQL이 검사 환경하에서 테스트될 때, 검사 데이터베이스가 가지고 있는 데이터는 제품 데이터베이스 <br />
를 반영해야 한다. 비실제적인 데이터를 가지고 테스트된 SQL문은 제품 안에서는 다르게 작동할 수 <br />
있다. 엄격한 테스트를 보장하기 위해서는, 검사 환경하에서의 데이터 분포는 반드시 제품 환경에서 <br />
의 분포와 밀접하게 닮아야 한다. </p>
<p>3.동일한 SQL을 사용하라. <br />
가능한한 BIND VARIABLE, STORED PROCEDURE, PACKAGE의 이점을 활용하라. IDENTICAL SQL문 <br />
의 이점은 PARSING이 불필요하기에 데이터베이스 서버안에서 메모리 사용의 축소와 빠른 수행을 <br />
포함한다. 예로서 아래의 SQL 문은 IDENTICAL하지 않다. </p>
<p>SELECT * FROM EMPLOYEE WHERE EMPID = 10; <br />
SELECT * FROM EMPLOYEE WHERE EMPID = 10; <br />
SELECT * FROM EMPLOYEE WHERE EMPID = 20; </p>
<p>그러나 I_EMPID라고 이름 주어진 BIND VARIABLE을 사용하면 SQL 문은 이렇게 된다. <br />
SELECT * FROM EMPLOYEE WHERE EMPID = :I_EMPID; </p>
<p>4.주의 깊게 인덱스를 사용하라. <br />
테이블상에 모든 필요한 인덱스는 생성되어야 한다. 하지만 너무 많은 인덱스는 성능을 떨어뜨릴 <br />
수 있다. 그러면 어떻게 인덱스를 만들 칼럼을 선택해야 하는가? </p>
<p>*최종 사용자에 의해 사용되는 어플리케이션 SQL과 쿼리의 WHERE 절에서 빈번하게 사용되는 칼럼 <br />
에 인덱스를 만들어야 한다. </p>
<p>*SQL 문에서 자주 테이블을 JOIN하는데 사용되는 칼럼은 인덱스되어야 한다. </p>
<p>*같은 값을 가지는 ROW가 적은 비율을 가지는 칼럼에 인덱스를 사용하라. </p>
<p>*쿼리의 WHERE 절에서 오직 함수와 OPERATOR로 사용되는 칼럼에는 인덱스를 만들면 안된다. </p>
<p>*자주 변경되거나 인덱스를 만들때 얻는 효율성보다 삽입, 갱신, 삭제로 인해 잃는 효율성이 더 큰 <br />
칼럼에는 인덱스를 만들면 안된다. 이러한 OPERATION은 인덱스를 유지하기 위한 필요 때문에 느려 <br />
진다. </p>
<p>*UNIQUE 인덱스는 더 나은 선택성 때문에 NONUNIQUE 인덱스보다 좋다. PRIMARY KEY 칼럼에 <br />
UNIQUE 인덱스를 사용한다. 그리고 FOREIGN KEY 칼럼과 WHERE 절에서 자주 사용되는 칼럼에는 <br />
NONUNIQUE 인덱스를 사용한다. </p>
<p>5.가용한 인덱스 PATH를 만들어라 <br />
인덱스를 사용하기 위해서는 기술한 SQL문을 이용할 수 있는 식으로 SQL을 작성하라. OPTIMIZER는 <br />
인덱스가 존재하기 때문에 인덱스를 사용하는 ACESS PATH를 사용할 수 없다. 따라서 ACCESS PATH <br />
는 반드시 SQL이 사용할 수 있게 만들어 져야 한다. SQL HINT를 사용하는 것은 인덱스 사용을 <br />
보증해주는 방법중 하나이다. 특정 ACCESS PATH를 선택하기 위한 다음의 힌트를 참고 하라 </p>
<p>6.가능하면 EXPLAIN과 TKPROF를 사용하라 <br />
만약 SQL문이 잘 다듬어지지 않았다면 비록 오라클 데이터베이스가 잘 짜여져 있어도 효율성이 떨어 <br />
질 것이다. 이럴 경우 EXPLAIN TKPROF에 능숙해져야 한다. EXPALIN PLAN은 SQL이 사용하는 <br />
ACCESS PATH를 발견할 수 있게 해주고 TKPROF는 실제 PERFORMANEC의 통계치를 보여준다. <br />
이 TOOL은 오라클 서버 소프트웨어에 포함되어 있고 SQL의 성능을 향상시켜 준다. </p>
<p>7.OPTIMIZER를 이해하라. <br />
SQL은 RULE-BASED나 COST-BASED중 하나를 이용해서 기동된다.기존의 소프트웨어는 RULE BASED <br />
방식을 채택하고 있다. 그리고 많은 오라클 소프트웨어가 이러한 방식을 오랫동안 사용해 왔다. <br />
그러나 새로 출시된 소프트웨어에 대해서는 COST BASED 방식의 OPTIMIZER를 고려해야 한다. <br />
오라클은 새로 출시되는 프로그램을 COST BASED방식으로 업그레이드 시켜왔으며 이러한 방식은 <br />
시스템을 훨씬 더 안정적으로 만들었다. 만약 COST BASED방식의 OPTIMIZER를 사용한다면 반드시 <br />
ANALYZE 스키마를 정기적으로 사용해야 한다. ANALYZE스키마는 데이터베이스 통계를 데이터 사전 <br />
테이블에 기록하는 역할을 수행하며 그렇게 되면 COST BASED OPTIMIZER가 그것을 사용하게 <br />
된다. SQL은 COST BASED OPTIMIZER를 사용할 때만 잘 조정될 수 있다. 만약 RULE BASED에서 <br />
COST BASED로 바꾸고 싶다면 데이터베이스를 사용하는 모든 소프트웨어의 모든 SQL문의 성능을 <br />
평가해 보아야 한다. </p>
<p>8.지엽적으로 동작하더라도 전역적으로 생각하라 <br />
항상 주의할 것은 하나의 SQL문을 조정하기 위해 생긴 데이터베이스안의 변화는 다른 응용프로그램 <br />
이나 다른 사용자가 이용하는 다른 명령문에 영향을 미친다는 사실이다. </p>
<p>9.WHERE절은 매우 중요하다. <br />
비록 인덱스가 가용하다고 해도 다음의 WHERE 절은 그 인덱스 ACCESS PATH 를 사용하지 않는다. <br />
(즉 COL1 과 COL2는 같은 테이블에 있으며 인덱스는 COL1에 만들어진다.) </p>
<p>COL1 &gt; COL2 <br />
COL1 &lt; COL2 <br />
COL1 &gt; = COL2 <br />
COL1 &lt;= COL2 <br />
COL1 IS NULL <br />
COL1 IS NOT NULL. </p>
<p>인덱스는 NULL값을 갖는 칼럼에는 ROWID를 저장하지 않는다. 따라서 NULL값을 갖는 ROW를 검색할 <br />
때는 인덱스를 사용하지 못한다. </p>
<p>COL1 NOT IN (VALUE1, VALUE2 ) <br />
COL1 != EXPRESSION <br />
COL1 LIKE &#8216;%PATTERN&#8217;. </p>
<p>이럴 경우 THE LEADING EDGE OF THE INDEX(?) 는 작동되지 않고 인덱스가 사용되지 못하게 한 <br />
다. 한편 COL1 LIKE &#8216;PATTERN %&#8217;이나 COL1 LIKE &#8216;PATTERN % PATTERN%&#8217; 는 한정된 인덱스 <br />
스캔을 수행하기 때문에 인덱스를 사용할 수 있다. </p>
<p>NOT EXISTS SUBQUERY <br />
EXPRESSION1 = EXPRESSION2. </p>
<p>인덱스된 컬럼을 포함하는 표현(EXPRESSION), 함수, 계산(CALCULATIONS)은 인덱스를 사용하지 <br />
못한다. 다음의 예에서 보면 UPPER SQL 함수를 사용하면 인덱스 스캔을 사용할 수 없고 <br />
FULL TABLE SCAN으로 끝나고 만다. </p>
<p>SELECT DEPT_NAME <br />
FROM DEPARTMENT <br />
WHERE UPPER(DEPT_NAME) LIKE &#8216;SALES%&#8217;; </p>
<p>10.레코드 필터링을 위해서는 HAVING보다는 WHERE를 사용하라 <br />
인덱스가 걸려있는 칼럼에는 GROUP BY와 같이 HAVING절을 사용하지 마라. 이 경우 인덱스는 사용 <br />
되지 않는다. 또한 WHERE절로 된 ROW를 사용하지 마라. 만약 EMP테이블이 DEPTID컬럼에 인덱스 <br />
를 가지고 있다면 다음 질의는 HAVING 절을 이용하지 못한다. </p>
<p>SELECT DEPTID, <br />
SUM(SALARY) <br />
FROM EMP <br />
GROUP BY DEPTID <br />
HAVING DEPTID = 100; </p>
<p>그러나 같은 질의가 인덱스를 사용하기 위해 다시 씌여질 수 있다. </p>
<p>SELECT DEPTID, <br />
SUM(SALARY) <br />
FROM EMP <br />
WHERE DEPTID = 100 <br />
GROUP BY DEPTID; </p>
<p>11. WHERE 절에 선행 INDEX 칼럼을 명시하라. <br />
복합 인덱스의 경우, 선행 인덱스가 WHERE절에 명시되어 있다면 쿼리는 그 인덱스 를 사용할 것이 <br />
다. 다음의 질의는 PART_NUM과 PRODUCT_ID 칼럼에 있는 PRIMARY KEY CONSTRAINT에 기초한 <br />
복합 인덱스를 이용할 것이다. </p>
<p>SELECT * <br />
FROM PARTS <br />
WHERE PART_NUM = 100; </p>
<p>반면, 다음의 쿼리는 복합인덱스를 사용하지 않는다. </p>
<p>SELECT * <br />
FROM PARTS <br />
WHERE PRODUCT_ID = 5555; </p>
<p>같은 요청(REQUEST)이 인덱스를 이용하기 위해 다시 씌어 질 수 있다. 다음 질의의 경우, <br />
PART_NUM컬럼은 항상 0 보다 큰 값을 가질것이다. </p>
<p>SELECT * <br />
FROM PARTS <br />
WHERE PART_NUM &gt; 0 <br />
AND PRODUCT_ID = 5555; </p>
<p>12.인덱스 SCAN과 FULL TABLE SCAN을 평가하라. <br />
한 행(ROW)의 15% 이상을 검색하는 경우에는 FULL TABLE SCAN이 INDEX ACESS PATH보다 빠르 <br />
다. 이런 경우, SQL이 FULL TABLE SCAN을 이용할 수 있도록 여러분 스스로 SQL을 작성하라. <br />
다음의 명령문은 비록 인덱스가 SALARY COLUMN에 만들어져 있어도 인덱스 SCAN을 사용하지 않을 <br />
것이다. 첫 번째 SQL에서, FULL HINT를 사용한다면 오라클은 FULL TABLE SCAN을 수행할 것이 <br />
다. 인덱스의 사용이 나쁜 점이 더 많다면 아래의 기술을 이용해서 인덱스 수행을 막을수 있다. </p>
<p>SELECT * &#8211;+FULL <br />
FROM EMP <br />
WHERE SALARY = 50000; </p>
<p>SELECT * <br />
FROM EMP <br />
WHERE SALARY+0 = 50000; </p>
<p>다음의 명령문은 비록 인덱스가 SS# COLUMN에 있어도 인덱스 SCAN을 사용하지 않을 것이다. </p>
<p>SELECT * <br />
FROM EMP <br />
WHERE SS# || &#8216; &#8216; = &#8217;111-22-333&#8242;; </p>
<p>오라클이 불분명한 데이터 변환을 수행해야 하는 경우 인덱스가 항상 사용되지않는 것은 아니다. <br />
다음의 예를 보면, EMP 칼럼에 있는 SALARY는 숫자형 칼럼이고 문자형이 숫자값으로 변환된다. </p>
<p>SELECT * <br />
FROM EMP <br />
WHERE SALARY = &#8217;50000&#8242;; </p>
<p>테이블의 행이 15%이거나 그보다 작을 경우 인덱스 스캔은 보다 잘 수행 될 것이다. 왜냐 하면 인덱 <br />
스 스캔은 검색된 행(ROW)하나 하나 마다 다중의 논리적인 읽기 검색(READ)을 할 것이기 때문이 <br />
다. 그러나 FULL TABLE SCAN은 하나의 논리적 인 읽기 검색 영역 안의 BLOCK에 있는 모든 행들을 <br />
읽을 수 있다. 그래서 테이블의 많은 행들에 접근해야 하는 경우에는 FULL TABLE SCAN이 낫다. <br />
예로 다음의 경우를 보자. 만약 EMP TABLE과 그 테이블의 모든 인덱스에 대해 ANALYZE라는 명령어 <br />
가 수행된다면, 오라클은 데이터 사전인 USER_TABLES와 USER_INDEXES에 다음과 같은 통계치를 <br />
산출해 낸다. </p>
<p>TABLE STATISTICS: <br />
NUM_ROWS = 1000 <br />
BLOCKS = 100 </p>
<p>INDEX STATISTICS: </p>
<p>BLEVEL = 2 <br />
AVG_LEAF_BLOCKS_PER_KEY = 1 <br />
AVG_DATA_BLOCKS_PER_KEY = 1 </p>
<p>이러한 통계치에 근거해서, 아래에 보이는 것이 각각의 다른 SCAN에 대한 논리적인 읽기(READ)-즉 <br />
ACESS된 BLOCK이 될 것이다. </p>
<p>USE OF INDEX TO RETURN ONE ROW = 3 </p>
<p>(BLEVEL+(AVG_LEAF_BLOCKS_PER_KEY &#8211; 1) + <br />
AVG_DATA_PER_KEY </p>
<p>FULL TABLE SCAN = 100 <br />
(BLOCKS) </p>
<p>USE OF INDEX TO RETURN ALL ROWS = 3000 <br />
(NUM_ROWS * BLOCKS ACCESSED TO RETURN ONE ROW USING INDEX) </p>
<p>13. 인덱스 스캔에 ORDER BY를 사용하라 <br />
오라클의 OPTIMIZER는 , 만약 ORDER BY라는 절이 인덱스된 칼럼에 있다면 인덱스 스캔을 사용할 <br />
것이다. 아래의 질의는 이러한 점을 보여 주는 것인데 이 질의는 비록 그 칼럼이 WHERE 절에 명시 <br />
되어 있지 않다고 해도 EMPID컬럼에 있는 가용한 인덱스를 사용할 것이다. 이 질의는 인덱스로부 <br />
터 각각의 ROWID를 검색하고 그 ROWID를 사용하는 테이블에 접근한다. </p>
<p>SELECT SALARY <br />
FROM EMP <br />
ORDER BY EMPID; </p>
<p>만약 이 질의가 제대로 작동하지 않는다면, 당신은 위에서 명시되었던 FULL HINT를 사용하는 같은 질의를 다시 작성함으로써 다른 대안들을 이용해 볼 수 있다. </p>
<p>
14. 자신의 데이터를 알아라 <br />
내가 이미 설명한 것처럼, 당신은 당신의 데이터를 상세하게 알고 있어야 한다.예를 들어 당신이 <br />
BOXER라는 테이블을 가지고 있고 그 테이블이 유일하지 않은 인덱스를 가진 SEX라는 컬럼과 <br />
BOXER_NAME이라는 두 개의 테이블을 가지고 있다고 가정해 보자. 만약 그 테이블에 같은 수의 <br />
남자, 여자 복서가 있다면 오라클이 FULL TABLE SCAN을 수행하는 경우 다음의 질의가 훨씬 빠를 <br />
것이다. </p>
<p>SELECT BOXER_NAME <br />
FROM BOXER <br />
WHERE SEX = &#8216;F&#8217;; </p>
<p>당신은 다음과 같이 기술함으로써 질의가 FULL TABLE SCAN을 수행하는지를 확실하게 해둘수 있다. </p>
<p>SELECT BOXER_NAME &#8211;+ FULL <br />
FROM BOXER <br />
WHERE SEX = &#8216;F&#8217;; </p>
<p>만약 테이블에 980 명의 남성 복서 데이터가 있다면, 질의는 인덱스 SCAN으로 끝나기 때문에 <br />
아래형식의 질의가 더 빠를 것이다. </p>
<p>SELECT BOXER_NAME &#8211;+ INDEX (BOXER BOXER_SEX) <br />
FROM BOXER <br />
WHERE SEX = &#8216;F&#8217;; </p>
<p>이 예는 데이터의 분포에 대해 잘 알고 있는 것이 얼마나 중요한 가를 예시해 준다. 데이터가 많아지고(GROW) 데이터 분포가<br />
변화하는 것처럼 SQL 도 매우 다양할 것이다. 오라클은 OPTIMIZER 가 테이블에 있는 데이터의 분포를 잘 인식하고 적절한<br />
실행 계획을 선택하도록 하기 위해 오라클 7.3 에 HISTOGRAMS라는 기능을 추가했다. </p>
<p>15. KNOW WHEN TO USE LARGE-TABLE SCANS. <br />
작거나 큰 테이블에서 행들을 추출할 때, 전체 테이블의 검색은 인텍스를 사용한 검색보다 성능이 <br />
더 좋을 수도 있다. 매우 큰 테이블의 인덱스 검색은 수많은 인덱스와 테이블 블록의 검색이 필요할 <br />
수도 있다. 이러한 블록들이 데이터베이 스 버퍼 캐쉬에 이동되면 가능한한 오래도록 그곳에 머무른 <br />
다. 그래서 이러한 블록들이 다른 질의등에 필요하지 않을 수도 있기 때문에, 데이터베이스 버퍼 <br />
히트 비율이 감소하며 다중 사용자 시스템의 성능도 저하되기도 한다. 그러나 전체 테이블 검색에 <br />
의해서 읽혀진 블록들은 데이터베이스 버퍼 캐쉬에서 일찍 제거가 되므로 데이터베이스 버퍼 캐쉬 <br />
히트 비율은 영향을 받지 않게 된다. </p>
<p>16. MINIMIZE TABLE PASSES. <br />
보통, SQL질의시 참조하는 테이블의 숫자를 줄임으로 성능을 향상시킨다. 참조되는 테이블의 숫자 <br />
가 적을수록 질의는 빨라진다. 예를 들면 NAME, STATUS, PARENT_INCOME, SELF_INCOME의 네개 <br />
의 컬럼으로 이루어진 학생 테이블 에서 부모님에 의존하는 학생과 독립한 학생의 이름과 수입에 <br />
대해서 질의시, 이 학생 테이블을 두번 참조하여 질의하게 된다.. <br />
SELECT NAME, PARENT_INCOME <br />
FROM STUDENT <br />
WHERE STATUS = 1 <br />
UNION <br />
SELECT NAME, SELF_INCOME <br />
FROM STUDENT <br />
WHERE STATUS = 0; <br />
( NAME이 프라이머리 키이며, STATUS는 독립한 학생의 경우는 1, 부모님에 의존적인 학생은 0으로 <br />
표시한다) <br />
위의 같은 결과를 테이블을 두번 참조하지 않고도 질의 할 수 있다. </p>
<p>SELECT NAME,PARENT_INCOME*STATUS + SELF_INCOME(1-STATUS) <br />
FROM STUDENT; </p>
<p>17. JOIN TABLES IN THE PROPER ORDER. <br />
다수의 테이블 조인시 테이블들의 조인되는 순서는 매우 중요하다. 전반적으로, 올바른 순서로 테이 <br />
블이 조인되었다면 적은 수의 행들이 질의시 참조된다. 언제나 다수의 조인된 테이블들을 질의시 <br />
우선 엄격하게 조사하여 행들의 숫자를 최대한으로 줄인다. 이러한 방법으로 옵티마이저는 조인의 <br />
차후 단계에서 적은 행들을 조사하게 된다. 뿐만 아니라, 여러 조인을 포함하는 LOOP JOIN에서는 <br />
가장 먼저 참조되는 테이블(DRIVING TABLE)이 행들을 최소한으로 리턴하도록 해야한다. 그리고, <br />
마스터와 상세 테이블 조인시에는(예를 들면 ORDER &amp; ORDER LINE ITEM TABLES) 마스터 테이블 <br />
을 먼저 연결 시켜야 한다. 규칙에 근거한 옵티마이저의 경우에는 FROM CLAUSE의 마지막 테이블 <br />
이 NESTED LOOP JOIN의 DRIVING TABLE이 된다. NESTED LOOP JOIN이 필요한 경우에는 LOOP <br />
의 안쪽의 테이블에는 인텍스를 이용하는 것을 고려할 만하다. EXPLAIN PLAN과 TKPROF는 조인 <br />
타입, 조인 테이블 순서, 조인의 단계별 처리된 행들의 숫자들을 나타낸다. <br />
비용에 근거한 옵티마이저의 경우에는 WHERE CLAUSE에 보여지는 테이블의 순서는 옵티마이저가 <br />
가장 최적의 실행 계획을 찾으려고 하는 것과 상관 없다. 조인되는 테이블의 순서를 통제하기 위해 <br />
서 ORDERED HINT를 사용하는 것이 낫다. </p>
<p>SELECT ORDERS.CUSTID, ORDERS.ORDERNO, <br />
ORDER_LINE_ITEMS.PRODUCTNO &#8211;+ORDERED <br />
FROM ORDERS, ORDER_LINE_ITEMS <br />
WHERE ORDERS.ORDERNO = ORDER_LINE_ITEMS.ORDERNO; </p>
<p>18. USE INDEX-ONLY SEARCHES WHEN POSSIBLE. <br />
가능하다면, 인덱스만을 이용하여 질의를 사용하라. 옵티마이저는 오직 인덱스만을 찾을 것이다. <br />
옵티마이저는 SQL을 만족시키는 모든 정보를 인덱스에서 찾을수 있을때,인덱스만을 이용할 것이다. <br />
예를들면, EMP테이블이 LANME과 FNAME의 열에 복합 인덱스를 가지고 있다면 다음의 질의는 <br />
인덱스만은 이용할 것이다. </p>
<p>SELECT FNAME <br />
FROM EMP <br />
WHERE LNAME = &#8216;SMITH&#8217;; </p>
<p>반면에 다음의 질의는 인덱스와 테이블을 모두 참조한다. </p>
<p>SELECT FNAME , SALARY <br />
FROM EMP <br />
WHERE LNAME = &#8216;SMITH&#8217;; </p>
<p>19. REDUNDANCY IS GOOD. </p>
<p>WHERE CLAUSE에 가능한한 많은 정보를 제공하라. 예를 들면 WHERE COL1 = COL2 AND COL1 = 10 <br />
이라면 옵티마이저는 COL2=10이라고 추론하지만, WHERE COL1 = COL2 AND COL2 = COL3이면 <br />
COL1=COL3이라고 초론하지는 않는다. </p>
<p>20. KEEP IT SIMPLE, STUPID. <br />
가능하면 SQL문을 간단하게 만들라. 매우 복잡한 SQL문은 옵티마이저를 무력화시킬 수도 있다. <br />
때로는 다수의 간단한 SQL문이 단일의 복잡한 SQL문보다 성능이 좋을 수도 있다. <br />
오라클의 비용에 근거한 옵티마이저는 아직은 완벽하지않다. 그래서 EXPLAIN PLAN에 주의를 <br />
기울여야 한다. 여기서 비용이란 상대적인 개념이기에 정확히 그것이 무엇을 의미하는지 알지 <br />
목한다. 하지만 분명한 것은 적은 비용이 보다 좋은 성능을 의미한다는 것이다. <br />
종종 임시 테이블을 사용하여 많은 테이블들을 포함하는 복잡한 SQL 조인을 쪼개는 것이 효율적일 <br />
수도 있다. 예를 들면, 조인이 대량의 데이터가 있는 8개의 테이블을 포함할 때, 복잡한 SQL을 두 <br />
세개의 SQL로 쪼개는 것이 낫을 수 있다. 각각의 질의는 많아야 네개정도의 테이블들을 포함하며 <br />
중간 값을 저장 하는 것이 낫을 수 있다. </p>
<p>21. YOU CAN REACH THE SAME DESTINATION IN DIFFERENT WAYS. <br />
많은 경우에, 하나 이상의 SQL문은 의도한 같은 결과를 줄 수 있다. 각각의 SQL은 다른 접근 경로 <br />
를 사용하며 다르게 수행한다. 예를들면, MINUS(-) 산술자는 WHERE NOT IN (SELECT ) OR <br />
ERE NOT EXISTS 보다 더 빠르다. <br />
예를들면, STATE와 AREA_CODE에 각각 다른 인덱스가 걸려 있다. 인덱스에도 불구하고 다음의 질의 <br />
는 NOT IN의 사용으로 인해 테이블 전체를 조사하게된다. <br />
SELECT CUSTOMER_ID <br />
FROM CUSTOMERS <br />
WHERE STATE IN (&#8216;VA&#8217;, &#8216;DC&#8217;, &#8216;MD&#8217;) <br />
AND AREA_CODE NOT IN (804, 410); </p>
<p>그러나 같은 질의가 다음 처럼 쓰여진다면 인덱스를 사용하게 된다 <br />
SELECT CUSTOMER_ID <br />
FROM CUSTOMERS <br />
WHERE STATE IN (&#8216;VA&#8217;, &#8216;DC&#8217;, &#8216;MD&#8217;) <br />
MINUS <br />
SELECT CUSTOMER_ID <br />
FROM CUSTOMERS <br />
WHERE AREA_CODE IN (804, 410); </p>
<p>WHERE절에 OR을 포함한다면 OR대신에 UNION을 사용할 수 있다. 그래서, SQL 질의를 수행하기 <br />
전에 먼저 실행계획을 조심스럽게 평가해야 한다. 이러한 평가는 EXPLAIN PLAN AND TKPROF를 이 <br />
용하여 할 수 있다. </p>
<p>22. USE THE SPECIAL COLUMNS. <br />
ROWID AND ROWNUM 열을 이용하라. ROWID를 이용하는 것이 가장 빠르다. <br />
예를들면, ROWID를 이용한 UPDATE는 다음과 같다. </p>
<p>SELECT ROWID, SALARY <br />
INTO TEMP_ROWID, TEMP_SALARY <br />
FROM EMPLOYEE; </p>
<p>UPDATE EMPLOYEE <br />
SET SALARY = TEMP_SALARY * 1.5 <br />
WHERE ROWID = TEMP_ROWID; </p>
<p>ROWID값은 데이터베이스에서 언제나 같지는 않다. 그래서, SQL이나 응용 프로그램이용시 ROWID값 <br />
을 절대화 시키지 말라. 리턴되는 행들의 숫자를 제한 시키기위해 ROWNUM을 이용하라. 만약에 리턴 <br />
되는 행들을 정확히 모른다면 리턴되는 행들의 숫자를 제한하기위해 ROWNUM을 사용하라 <br />
다음의 질의는 100개 이상의 행들을 리턴하지는 않는다. <br />
SELECT EMPLOYE.SS#, DEPARTMENT.DEPT_NAME <br />
FROM EMPLOYEE, DEPENDENT <br />
WHERE EMPLOYEE.DEPT_ID = DEPARTMENT.DEPT_ID <br />
AND ROWNUM &lt; 100; </p>
<p>23.함축적인 커서대신 명시적인 커서를 사용하라. <br />
함축적 커서는 여분의 FETCH를 발생시킨다. 명시적 커서는 DECLARE, OPEN, FETCH와 CLOSE <br />
CURSOR문을 사용하여 개발자에 의해서 생성된다. 함축 커서는 DELETE, UPDATE, INSERT와 <br />
SELECT문을 사용하면 오라클에 의해서 생성된다. </p>
<p>24.오라클 병렬 쿼리 옵션을 찾아서 이용하라. <br />
병렬 쿼리 옵션을 사용하면, 보다 빠른 성능으로 SQL을 병렬로 실행할 수 있다. <br />
오라클 7에서는, 오직 FULL TABLE SCAN에 기반한 쿼리만이 병렬로 수행될 수 있다. <br />
오라클 8에서는, 인덱스가 분할되어있다면 INDEXED RANGE SCANS에 기반한 쿼리도 병렬로 처리될 <br />
수 있다. 병렬 쿼리 옵션은 다수의 디스크 드라이버를 포함하는 SMP와 MPP SYSTEM에서만 사용될 <br />
수 있다. </p>
<p>오라클 서버는 많은 우수한 특성을 가지고 있지만, 이러한 특성의 존재만으로는 빠른 성능을 보장하 <br />
지 않는다. 이러한 특성을 위해서 데이터베이스를 조정해야하며 특성을 이용하기 위해 특별하게 SQL <br />
을 작성해야 한다. 예를 들면, 다음의 SQL은 병렬로 수행될 수 있다. </p>
<p>SELECT * &#8211;+PARALLEL(ORDERS,6) <br />
FROM ORDERS; </p>
<p>25.네트웍 소통량을 줄이고 한번에 처리되는 작업량을 늘려라. <br />
ARRAY PROCESSING과 PL/SQL BLOCK을 사용하면 보다 나은 성능을 얻을 수 있고 네트웍 소통량을 <br />
줄인다. ARRAY PROCESSING은 하나의 SQL문으로 많은 ROW를 처리할 수 있게 한다. 예를 들면, <br />
INSERT문에서 배열을 사용하면 테이블내의 1,000 ROW를 삽입할 수 있다. 이러한 기술을 사용하면 <br />
주요한 성능 향상을 클라이언트/서버와 배치시스템에서 얻어질 수 있다. </p>
<p>복합 SQL문은 과도한 네트웍 소통을 유발할 수 있다. 그러나 만일 SQL문이 단일 PL/SQL 블록안에 <br />
있다면, 전체 블록은 오라클 서버에 보내져서 그곳에서 수행되고, 결과는 클라이언트의 <br />
APPLICATION에게 돌아온다. </p>
<p>개발자와 사용자는 종종 SQL을 데이터베이스에서 데이터를 검색하고 전송하는 간단한 방법으로 사용 <br />
한다. 때때로 직접적으로 SQL을 작성하지 않고 코드 발생기를 사용하여 작성한 APPLICATION은 심 <br />
각한 성능 문제를 일으킨다. 이러한 성능감퇴는 데이터베이스가 커지면서 증가한다. </p>
<p>SQL은 유연하기 때문에, 다양한 SQL문으로 같은 결과를 얻을 수 있다. 그러나 어떤 문은 다른 것보 <br />
다 더 효율적이다. 여기에 기술된 팁과 기법을 사용하면 빠르게 사용자에게 정보를 제공할 수 있는 <br />
APPLICATION과 리포트를 얻을 수 있다.</p>
<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://www.onuyi.net/blog/archives/117/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

