2012년 6월 29일 금요일

SQLite 의 모든 것 (1부) - 소개 및 FAQ(posting)

출처 : http://crystalcube.co.kr/89

소개



 
- SQLite 는 독립적이고, 서버가 필요 없으며, 특별한 설정을 할 필요도 없는, 트렌젝션이 가능한 SQL 데이타베이스 엔진으로 꾸준히 개발중인 Library 입니다. SQLite 의 코드는 공개되어 있고, 상업적이든 개인적이든, 어떤 용도로도 무료로 사용하실 수 있습니다. 현재 SQLite 는 꽤 유명한 프로젝트를 포함하여, 생각하는 것 이상으로 많은 프로그램에서 사용하고 있습니다.

접기
[Adebe]
 - Photoshop Lightroom 제품에서 파일 포맷으로 SQLite 를 사용하고 있습니다. 그리고 Adebe Integrated Runtime(AIR) 에서도 SQLite 는 표준으로 사용됩니다. 또한 Acrobat Reader 에서도 SQLite 를 사용하는 것으로 알려져 있습니다.

[AIRBUS]
 - A350 XWB 라는 항공 소프트웨어에서 SQLite 를 사용하고 있습니다.

[Apple]
 - Apple 은 Apple Mail, Safari, Aperture 등 Mac OS X 의 수 많은 곳에서 SQLite 를 쓰고 있습니다. iPhone 과 iPod touch 그리고 iTunes 에서도 사용하고 있습니다.

[FireFox]
 - 파이어폭스 브라우저에서 개인 meta-data 를 저장할 때 SQLite 를 사용하고 있으며, Mozilla 의 Thunderbird Email Reader 에서도 사용하고 있습니다.


[General Electric]
 - General Electric 에서도 몇몇 제품이나 다른 곳에서 SQLite 를 쓰고 있는 것으로 알고 있습니다.

[Google]
 - Google 은 Desktop for Mac 과 Google Gears, 휴대폰 Android OS, 크롬 웹 브라우저에서 사용하고 있습니다.

[Intuit]
 - QuickBooks 와 TurboTax 에서 사용자 에러를 수집하기 위해서 SQLite 를 사용하고 있습니다.

[McAfee]
 - 백신 프로그램에서 SQLite 를 사용하고 있습니다.

[Microsoft]
 -  SQLite 의 메일링 리스트를 보면 적어도 하나 이상의 Microsoft 게임 프로그램 개발자 그룹에서 사용하고 있는 것으로 생각됩니다. 실제로 게임이 릴리스되거나 아직도 SQLite 를 쓰고 있다면 말이죠.

[PHP]
 - 유명한 프로그래밍 언어인 PHP 는 SQLite2 와 SQLite3 를 포함하고 있습니다.

[Python] 
 - SQLite 는 Python 2.5 부터 포함되어 있습니다.

[REALbasic]
 - REALbasic 프로그래밍 환경은 AES 암호화를 지원하는 SQLite 버전을  포함하고 있습니다.

[skype]
 - Mac OS X 와 Windows 의 Skype 클라이언트에서 SQLite 를 사용하고 있습니다.

[Sun]
 - Solaris 10 에서는 서비스 관리 시설에서 SQLite 저장 포멧을 사용하고 있습니다. 그래서 unix 의 고전적인 파일인 /etc/inittab 파일을 SQLite 데이타베이스로 대체하였습니다. 
접기
 - SQLite 는 SQL 데이타베이스 엔진을 내장하고 있습니다. 수 많은 SQL 데이타베이스와는 다르게, SQLite 는 별도의 서버 프로세스를 가지고 있지 않고, 일반 디스크 파일을 직접 읽고 씁니다. SQLite 의 데이타베이스는 오직 한 개의 파일에 멀티 테이블, 색인, 트리거, 뷰 등을 가지고 있습니다.그리고 데이타베이스 파일은 크로스 플랫폼을 지원한기 때문에, 32비트 - 64비트 또는 big-endian little-endian 아키텍처에서 서로 사용할 수 있습니다. 이것이 Applictiion File Format 으로 SQLite 가 사랑받는 이유입니다. 

- SQLite 는 매우 작은 라이브러리입니다. 컴파일러 세팅이나 타겟 플렛폼에 따라서 조금의 차이는 있겠지만, 350 kbye 정도밖에 되지 않습니다. 옵션 기능을 제거하면 200 kbyte 이하로도 만들 수 있습니다. 또한 실행시에는 메모리 스택영역은 4kbyte, 힙 영역은 100 kbyte 으로 매우 조금만 차지합니다. 이런 이유로 휴대폰, PDA, MP3 플레이어와 같이 메모리 제약적인 곳에서 SQLite 를 널리 쓰고 있습니다. 메모리와 성능은 서로 교환적입니다. 메모리 공간이 많을수록 속도는 빨라집니다. 그럼에도 불구하고 작은 메모리 환경에서도 우수한 속도를 자랑합니다.





FAQ

1. AUTOINCREMENT 필드는 어떻게 만드나요?
접기
쉽게 말하자면, INTEGER PRIMARY KEY 로 선언하면 됩니다.

테이블의 컬럼을 INTEGER PRIMARY KEY 로 선언을 하면, NULL 을 넣으면 자동적으로, 가장 마지막 행의 해당 컬럼의 값보다 1 큰 값이 채워집니다. 만약 테이블에 아무런 행도 없다면 1 이 들어갑니다. (integer key 의 최대값인 9223372036854775807 라면, 사용하고 있지 않는 키 중에서 랜덤으로 채워집니다.) 예를들어, 아래처럼 테이블을 만들 경우.

CREATE TABLE t1(
   a INTEGER PRIMARY KEY,
   b INTEGER
);

에서 아래 문장을 실행하면

   INSERT INTO v1 VALUES(NULL, 123);

논리적으로는 다음과 같은 의미입니다.

   INSERT INTO v1 VALUES((SELECT max(a) FROM f1) + 1, 123);

가장 마지막에 insert 한 오퍼레션의 integer key 값을 리턴해 주는 sqlite3_last_insert_rowid() 라는  함수가 있습니다.
접기


2. SQLite 에서 지원하는 자료형(data type)은 어떤 것들이 있나요? 
접기
SQLite 는 동적타입(dynamic typing) 을 사용합니다. INTEGER, REAL, TEXT, BLOB, NULL 을 저장할 수 있습니다.
접기


3. SQLite 은 이상하게도 integer 타입 컬럼에 문자열이 들어갑니다!
접기
그건 기능이지 버그가 아닙니다. SQLite 는 동적 타이핑(dynamic typing)을 사용합니다. 데이터 타입 제약을 강제하지 않습니다. 어떤 데이터도 아무 컬럼에나 들어갈 수 있습니다. 임의의 길이의 문자열을 integer 컬럼에, floating 소수를 boolean 컬럼에, date 를 character 컬럼에 넣을 수도 있습니다. CREATE TABLE 명령에서 선언한 컬럼의 data type 은 해당 컬럼에 들어갈 수 있는 자료형을 제한하지 않습니다. 어떤 컬럼에도 임의의 길이 문자열을 넣을 수 있습니다.(단, INTEGER PRIMARY KEY 로 선언된 컬럼에는 64-bit signed integer 만 들어갈 수 있습니다. INTEGER PRIMARY KEY 컬럼에 integer 가 아닌 다른값을 넣으면 오류가 발생합니다.)

SQLite 에서는 단지 선언한 컬럼에 어떤 형식의 값을 넣기를 선호하는지를 선언하는것 뿐 입니다. 그렇기 때문에 INTEGER 컬럼에 문자열을 넣으려고 하면, SQLite 는 문자열을 integer 로 변환 시킵니다. 만약 변환이 가능하면 변환된 integer 를 넣고 불가능하다면 문자열을 그냥 넣습니다. 이 기능을 type affinity 라고 부릅니다.
접기


4. 왜 SQLite 에서는 한 table 안에서 primary key 로 '0' 과 '0.0' 을 함께 사용 할 수 없나요?
접기
이 문제는 primary key 가 숫자 타입(numeric type)일 때 발생합니다. primary key 을 TEXT 타입으로 변경하면 됩니다.

모든 행은 공유한 primary key 를 가져야만 합니다. 숫자 타입의 컬럼에서는 SQLite 는 '0' 과 '0.0' 을 같은 값으로 생각합니다. 왜냐면 숫자에서는 두 값은 동일한 값이기 때문입니다.(이전 질문을 참고하세요) 이런 이유로 값은 고유하지 않게 됩니다.
접기


5. 여러 프로그램이나 한 프로그램의 여러 인스턴스에서 한 개의 database 파일을 동시에 접근할 수 있나요? 
접기
멀티 프로세스는 동시에 같은 데이터베이스를 가질 수 있습니다. 이 멀티 프로세스는 SELECT 를 동시에 할 수 있습니다. 하지만 데이타베이스의 변경은 순간적으로 오직 하나의 프로세스만 가능합니다.

SQLite 는 데이터베이스의 엑세스를 제어하기 위해서 reader/writer lock을 사용합니다.(reader/writer lock 이 부족한 Win95/98/ME 에서는 확률적 시물레이션(probabilistic simulation)으로 대체합니다.) 하지만 NFS 파일 시스템에서 데이타베이스 파일을 쥐고 있으면, 이 락 메카니즘이 제대로 동작하지 않을 수 있습니다. 많은 NFS 구현에서 fcntl() 파일 락킹이 깨졌기 때문입니다. NFS 에서는 다중 프로세스에서 동시에 데이타베이스 파일을 엑세스 하는 것을 피해야 합니다. Windows 에서 Microsoft 문서를 보면 Share.exe 데몬을 수행하지 않는 이상 FAT 파일 시스템에서는 락킹이 동작하지 않는다고 되어 있습니다. Windows 를 많이 경험한 사람들은 네트워크 파일 락은 매우 버그가 많고 독립적이지 않다고 말합니다. 그들이 말한게 사실이라면, SQLite 데이타베이스를 두 개 이상의 Windows 머신에서 공유해서 사용하는 것은 예상하지 못한 문제를 일으킬 것입니다.

 저희는 SQLite 만큼이나 많은 동시성을 지원하는 임베디드 SQL 데이타베이스 엔진이 없다는 것을 알고 있습니다. SQLite 는 여러 프로세스에서 동시에 데이타베이스 파일을 여는 것을 허용합니다. write 를 하는 모든 프로세스는 update 작업동안, 데이터베이스 파일의 락에 들어가야만 합니다. 하지만 대부분 수 millisecond 동안 입니다. 다른 프로세스는 앞 프로세스의 writer 작업이 끝나기를 기다리게 됩니다. 다른 임베디드 SQL 데이타베이스 엔진들은 형식적으로 한 데이터베이스에 대해서 한번에 오직 한 프로세스만 연결하도록 하고 있습니다.

그러나, client/server 데이터베이스 엔진(PostgreSQL, MySQL, Oracle 등)들은 일반적으로 동시에 여러 프로세스에서 한 데이터베이스에 대해 write 할 수 있는 고수준의 동시성을 지원합니다. client/server 데이터베이스에서는 항상 단일 서버 프로세스가 엑세스를 조율하기 때문에 가능합니다. 프로그램에서 수 많은 동시성을 필요로 한다면 client/server 데이타베이스를 고려하는게 나을 것입니다. 하지만 경험상 대부분의 프로그램은 개발자들이 생각한것 보다 훨씬 적은 동시성을 필요로 합니다.

기본적으로 SQLite 는 엑세스하려는 파일을 다른 프로세스가 락을 걸고 있으면, SQLITE_BUSY 를 리턴합니다. C 프로그래밍을 할 경우, sqlite_busy_handler() 또는 sqlite3_busy_timeout() API 를 사용하면 이것을 컨트롤 할 수 있습니다.
접기


6. SQLite 는 쓰레드에 안전(threadsafe)한가요?
접기
다중 쓰레드는 악이다(Threads are evil). 쓰지 마라.

SQLite 는 threadsafe 하다. 우리는 위에서 언급한것과 같이 수 맣은 사용자의 충고를 무시하고 쓰레드에 대해서 양보했습니다.  하지만 thread-safe 하기 위해서는 컴파일 시 SQLITE_THREADSAFE 프리프로세스 매크로가 1로 set 되어 있어야만 합니다. Windows 와 Linux 프리컴파일 바이너리 모두 이 방식으로 컴파일 됩니다. 만약 SQLite 바이너리가 threadsafe 로 컴파일 되었는지 모르겠다면, sqlite3_threadsafe() 인터페이스를 통해서 확인할 수 있습니다.

version 3.3.1 이전 버젼에서는, sqlite3 구조체는 sqlite3_opne() 함수를 호출한 쓰레드에서만 사용할 수 있었습니다. 물론 다른 쓰레드에서 이 구조체의 포인터를 넘겨받아도 불가능했습니다. 이유는 RedHat9 과 같은 대부분의 범용 쓰레드에서 제한(버그?)이 걸려있어서 였습니다. 이런 시스템에서는 특히 fcntl() 락의 경우 락을 만든 쓰레드가 아니면 lock 을 제거하거나 수정할 수 없습니다. 그리고 SQLite 가 동시성 제어를 위해서 fcntl() 락을 사용할 경우, 다른 쓰레드에서 데이터베이스 연결을 제거하면, 심각한 문제가 발생했습니다.

version 3.3.1 이 되어서야 다른 쓰레드에서 데이터베이스 연결을 해제하는 제한이 풀렸습니다. 하지만 fcntl() 락이 걸려있지 않을 때, 데이터베이스 커넥션을 해제하는 것이 좋습니다. 트렌젝션이 걸려있지 않고 모든 statement 가 finalized 되었다면 lock 이 걸려 있지 않다고 생각하시면 됩니다.

Unix 에서는 열려있는 SQLite 데이터베이스를 fork() 시스템 콜을 통해서 자식 프로세스에게 전달하면 안됩니다. 이렇게 하면 문제가 발생할 수 있습니다.
접기


7. SQLite 데이타베이스에 있는 모든 table 과 indices 를 출력하려면 어떻게 해야 하나요?
접기
sqlite3 커맨드라인 프로그램을 쓰고 있다면, ".tables" 를 하면 모든 테이블 리스트가 나옵니다. ".schema" 를 하면 모든 테이블과 색인들을 포함한 완벽한 데이터베이스의 스키마를 보실 수 있습니다. 이 커맨드 모두 표시할 테이블을 제한하는 LIKE 패턴과 함께 사용할 수 있습니다.

C/C++ 프로그램(또는 Tcl/Ruby/Perl/Python 에 반인딩 되는 스크립트)에서는 "SQLITE_MASTER" 이라는 특별한 테이블을 SELECT 함으로써 테이블과 index 이름을 엑세스 할 수 있습니다. 모든 SQLite 데이터베이스는 데이터베이스 스키마를 정의하고 있는 SQLITE_MASTER 이라는 이름의 테이블을 가지고 있습니다. SQLITE_MASTER 테이블은 다음과 같습니다.

    CREATE TABLE sqlite_master (
        type        TEXT,
        name      TEXT,
        tbl_name TEXT,
        rootpage  INTEGER,
        sql          TEXT
    ); 

 테이블에서는 type 필드는 항상 'table' 이고, name 필드는 테이블 이름입니다. 데이터베이스에서 모든 테이블 리스트를 얻기 위해서는 아래처럼 SELECT 커맨드를 이용하면 됩니다.

    SELECT name FROM sqlite_master
    WHERE type='table'
    ORDER BY name;

 색인(dicies)에서는 type 은 'index' 와 같고, name 은 index 이름이며, tbl_name 은 index 를 포함하고 있는 테이블 이름입니다. 테이블과 색인 둘다, sql 필드는 테이블 또는 인덱스를 만들때 사용한 CREATE TABLE 또는 CREATE INDEX 의 original 명령 입니다. 자동으로 생성된 색인(PRIMARY KEY 또는 UNIQUE 제한을 위해서 구현한)의 sql 필드는 NULL 입니다.

SQLITE_MASTER 테이블은 읽기전용입니다. UPDATE, INSERT, DELETE 를 사용해서 테이블을 변경 할 수 없습니다. 테이블은 CREATE TABLE, CREATE INDEX, DROP TABLE, DROP INDEX 커맨드들을 통해서 자동으로 업데이트 됩니다.

임시 테이블은 SQLITE_TABLE 테이블에 나타나지 않습니다. 임시 테이블과 그 색인들 그리고 트리거는 SQLITE_TEMP_MASTER 이라는 특별한 이름의 테이블을 사용합니다. SQLITE_TEMP_MASTER 은 SQLITE_MASTER 과 임시 테이블을 만든 프로그램에서만 보인다는 것을 제외하면 모두 동일합니다. 진짜건 임시건 둘다 테이블 리스트를 구하기 위해서는 아래와 같은 커맨드를 사용하면 됩니다.

    SELECT name FROM
        (SELECT * FROM sqlite_master UNION ALL
         SELECT * FROM sqlite_temp_master)
    WHERE type='table'
    ORDER BY name
접기


8. SQLite 데이타베이스의 사이즈 제한이 있나요?
접기
SQLite 의 모든 제한에 대해 설명되어 있는 limits.html 을 참고하시기 바랍니다.
접기


9. SQLite 에서 VARCHAR 의 최대 크기는 얼마인가요?
접기
SQLite 는 VARCHAR 의 문자열 길이에 대해서 제한하지 않습니다. , SQLite 에서는 VARCHAR(10) 으로 선언하고, 500 개의 문자를 넣더라도 괜찮습니다. 그리고 500 문자 모두 손실없이 그대로 저장합니다. 잘라내지 않습니다.
접기


10. SQLite 는 BLOB 타입을 지원하나요?
접기
SQLite version 3.0 이후 버젼에서는 컬럼에 BLOB 데이터를 저장 할 수 있습니다. 심지어 컬럼이 BLOB 이 아닌 다른 타입으로 선언되어 있어도 됩니다.
접기


11. SQLite 에 table 에서 컬럼을 추가하거나 삭제하려면 어떻게 해야 하나요?
접기
SQLite 는 제한적으로 ALTER TABLE 지원합니다. 테이블의 마지막에 컬럼을 추가하거나 테이블 이름을 변경하는 정도입니다. 테이블 구조를 복잡하게 변경해야 한다면, 테이블을 새로 만들어야 합니다. 임시 테이블에 데이터를 저장하고, 이전 테이블을 삭제, 그리고나서 새로 테이블을 만들어서 여기에 데이터를 집어 넣어야 합니다.

예를들어, "t1" 이라는 테이블에 "a", "b", "c" 라는 컬럼이 있고, 컬럼 "c" 를 삭제하려면, 아래처럼 하시면 됩니다. 

    BEGIN TRANSACTION;
    CREATE TEMPORARY TABLE t1_backup(a, b);
    INSERT INTO t1_backup SELECT a, b, FROM ta1;
    DROP TABLE t1;
    CREATE TABLE t1(a, b);
    INSERT INTO t1 SELECT a, b, FROM t1_backup;
    DROP TABLE t1_backup;
    COMMIT; 
접기


12. 많은 데이터를 지웠는데, 데이타 파일의 크기는 줄어들지 않습니다. 버그인가요?
접기
아닙니다. SQLite 데이터베이스에서 정보를 삭제할 경우, 사용하지 않는 디스크 공간은 내부적으로 "free-list" 에 등록되고, 다음에 데이터를 입력하면 그때 이 공간을 재사용합니다. 즉 디스크 공간은 사라지지 않습니다. 운영체제에 반납하지 않을 뿐입니다.

만약 많은 양의 데이터를 삭제한 뒤에, 데이터베이스 파일의 크기를 줄이고 싶다면, VACUUM 명령을 사용하시면 됩니다. VACUUM 은 늘어난 데이터베이스를 재구성 합니다. free-list 를 비우고, 최소 파일 사이즈로 만듦니다. 그러나 VACUUM 을 수행하는데 약간의 시간이 소요되며(SQLite 가 개발된 Linux box 에서는 실험결과 1 메가바이트당 약 0.5초 정도가 소요되는 것을 나타났습니다.), 수행하는 동안 원판 파일의 두배 크기만큼의 가상공간이 필요하다는 것을 기억하시기 바랍니다.

SQLite version 3.1 에서는 auto_vacuum_pragma 를 사용해서 auto-vacuum 모드로 설정할 수 있습니다.
접기


13. 로열티를 지불하지 않고 SQLite 를 상업 프로그램을 만드는데 사용해도 되나요?
접기
네. SQLite 는 public domain 입니다. 소유권에 대해서는 코드의 어떤 부분에 대해서도 없습니다. 여러분이 하고싶은 그 어떤것을 하셔도 됩니다.
접기


14. 홑따옴표(') 문자를 포함한 문자열을 사용하려면 어떻게 해야 하나요?
접기
SQL 표준에서 홑따옴표는 두개의 홑따옴표로 escape 하도록 되어 있습니다. SQL 은 파스칼 프로그래밍 언어와 비슷합니다. SQLite 는 이 표준을 준수합니다. 예를 들면 다음과 같습니다.

    INSERT INTO xyz VALUES('5.0''clock'); 
접기


15. SQLITE_SCHEMA 에러는 무엇인가요? 그리고 왜 발생하나요?
접기

접기


16. ROUND(9.95, 1) 은 10.0 대신 9.9 가 리턴 됩니다. 9.95 를 반올림 해야 하는거 아닌가요?
접기

접기


17. SQLite 를 컴파일 할때, 수백개의 오류가 발생합니다. 코드에 문제가 있는게 아닌가요? 저질스런 코드 아닌가요?
접기

접기


18. 유니코드 문자에 대해서는 대소문자 구분없는 매칭(Case-insensitive matching)이 되지 않습니다.
접기

접기


19. INSERT 가 너무나 느립니다. 초당 겨우 열 개 정도 INSERT 할 수 있습니다.
접기

접기


20. 실수로 SQLite 데이타베이스에서 중요한 데이터를 지웠습니다. 복구 가능한가요?
접기

접기


21. SQLITE_CORRUPT 에러가 무엇인가요? 데이타베이스가 "malformed" 되었다는게 무슨 의미인가요? 그리고 왜 발생하는건가요?
접기

접기


22. SQLite 는 외래키(foreign keys)를 지원하나요?
접기

접기


23. SQLite 를 빌드할 때, 컴파일 옵션에 SQLITE_OMIT 를 사용하면 컴파일러에서 오류가 발생합니다. 
접기

접기


24. WHERE 절에 column1="column1" 이 동작하지 않는 것 같습니다. 왜냐면 column1 의 값이 "column1" 인 행 뿐만 아니라, 테이블의 모든 행이 리턴되기 때문입니다.
접기

접기


25. SQLite 에서 생성하는 문법 다이어그램(syntax diagrams)은 어떤가요?
접기
이 부분에 대해서는 http://wiki.tcl.tk/21708 에 잘 설명되어 있습니다.
접기


26. SQL 표준에서는 컬럼에서 NULL 이 하나 또는 그 이상이더라도 UNIQUE 을 적용하도록 되어 있습니다. 하지만 SQLite 에는 그렇지 않는 것 같습니다. 버그인가요?
접기

접기


27. SQLite 의 Export Control Calssification Number(ECCN) 은 무엇인가요?
접기

접기

댓글 없음:

댓글 쓰기