- 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 를 사용하면 이것을 컨트롤 할 수 있습니다.
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 에러는 무엇인가요? 그리고 왜 발생하나요?
준비된 SQL statement 가 더이상 유효하지 않거나, 실행할 수 없게되면 SQLITE_SCHEMA 에러가 리턴됩니다. 이 경우, statement 는 반드시 sqlite3_prepare() API를 사용해서 SQL로부터 다시 컴파일 되어야 합니다. SQLITE_SCHEMA 에러는 SQL 을 실행하기 위해서 sqlite3_prepare() 나 sqlite3_step() 를 사용할 때 발생합니다. sqlite3_exec() 를 실행했을때는 SQLITE_SCHEMA 에러가 발생하지 않습니다. 마찬가지로 sqlite3_prepare() 대신 sqlite3_prepare_v2() 를 사용할 경우에도 에러는 발생하지 않습니다.
sqlite3_prepare_v2() 는 prepared_statement 를 생성하는데, 이 prepared_statement 는 schema 가 변경되었을 때, 자동으로 알아서 재컴파일 됩니다. SQLITE_SCHEMA 에러를 관리하는 가장 쉬운 방법은 sqlit3_prepare() 대신 항상 sqlite3_prepare_v2() 를 사용하는 것입니다.
16. ROUND(9.95, 1) 은 10.0 대신 9.9 가 리턴 됩니다. 9.95 를 반올림 해야 하는거 아닌가요?
SQLite 는 2진수를 사용합니다. 그렇기 때문에 9.95 를 한정된 비트(bit)로 표현할 방법이 없습니다. 64-bit IEEE 부동소수점(SQLite 에서 사용하는 방식)으로 그나마 가장 근접하게 표현한 것이 9.949999999999999289457264239899814128875732421875 입니다. 그렇기 때문에 "9.95" 를 위에 언급한 것처럼 인식해 버립니다. 그리고 값은 아래로 반올림 되어버립니다.
부동소수점들을 표현할 때, 이런 문제들이 발생합니다. 기본적으로 알아 두셔야 할 것은 대부분의 분수값(10진수로 표현 가능한)들은 2진수로 표현 할 수 없습니다. 그렇기 때문에 2진수 중에서 그나마 가장 가까운 값을 사용하게 됩니다. 이것이 가장 근접하게 표현 할 수 있는 방식이지만, 때로 말씀하신 것처럼 예측한 결과와 다른 결과값이 나올 수 있습니다.
17. SQLite 를 컴파일 할때, 수백개의 오류가 발생합니다. 코드에 문제가 있는게 아닌가요? 저질스런 코드 아닌가요?
SQLite 의 품질검증은 컴파일러의 경고나 다른 분석툴의 정적 코드를 제외한 나머지 부분에 대해서 full-coverage testing 으로 완료했습니다. 다시 말해, SQLite 이 올바른 결과값을 준다고 자신합니다. 하지만 스타일적인 제약은 만족하지 않습니다. 대부분의 SQLite 코드 하부는 수 많은 테스트를 거쳤습니다. SQLite 는 독립된 테스트 수트만 수만번씩 테스트 하였으며, 파라미터 값을 포함한 SQL statemenets 를 수십억번씩 테스트 하였습니다. 그리고 나서 release 를 합니다. 개발자는 코드 검증툴을 사용해서 검증하고, 다방면으로 코드를 검증합니다. SQLite 에서 버그가 발견되면, 새로운 테스트 케이스를 추가시켜서 다시는 재발하지 않도록 관리하고 있습니다.
테스트를 진행하는 동안, SQLite 라이브러리는 특별한 방식으로 컴파일 됩니다. 테스트 스크립트를 만들어서 SQLite 가 명령 수행중 실패했을 때, 제대로 오류 처리를 하고 있는지 다방면으로 테스트합니다. 메모리 할당에 있어서도 꼼꼼히 추적하여, 오류가 났을때도 메모리 누수가 발생하지 않도록 하고 있습니다. 또한, 사용자 VFS 레이어를 가지고 운영체제에서 오류가 발생하거나 전원이 나갔을때도, 이런 이벤트들을 자동으로 인지해 처리하는지 시뮬레이션 합니다. 그리고 의도적으로 I/O 에러를 발생시켜서 잘 처리되는지도 확인합니다.
더불어 SQLite 는 리눅스에서 Valgrind 를 이용하여 실행시키고, 아무런 문제가 없음을 확인합니다.
어떤 사람들은 저희에게 모든 경고(warnings)들을 없애야 한다고 이야기합니다. 그래야 나중에 이 경고로부터 심각한 문제가 발생되는 걸 막을 수 있다고 합니다. 충분히 무슨 이야기인지 이해합니다. 하지만 답변을 하자면, 이런 모든 오류들은 이미 SQLite 개발에 사용하는 컴파일러(다양한 GCC 버전)에서는 발생하지 않는 것 들입니다. 컴파일러 경고는 저희 개발자들이 사용하지 않는 컴파일러에서 발생한 것들입니다.(예. MSVC)
18. 유니코드 문자에 대해서는 대소문자 구분없는 매칭(Case-insensitive matching)이 되지 않습니다.
SQLite 의 ASCII 문자 비교시 대소문자를 구분하지 않도록 기본 설정 되어 있습니다. 왜냐면 모든 유니코드에 대해서 대소문자 구분을 지원하려면, SQLite 라이브러리의 전체 사이즈 두배가 넘는 대소문자 변환 테이블과 로직이 들어가야 합니다. SQLite 개발자들은 모든 유니코드의 대소문자를 지원하는 프로그램은 아마도 필요한 테이블과 함수들을 포함하고 있을 거라고 생각합니다. 그렇기 때문에 SQLite 는 이를 지원하지 않습니다.
기본값으로 모든 유니코드의 대소문자를 지원하는 것 대신, SQLite 는 외부 유니코드 비교방식과 비교 루틴을 사용할 수 있도록 링크기능을 제공합니다. 프로그램에서 NOCASE 대조 순서(sqlite3_create_collation() 을 사용), like(), upper(), lower() 함수를 오버로드 할 수 있습니다. SQLite 소스코드에는 이런 오버로드를 위한 "ICU" 확장이 포함되어 있습니다. 또는 개발자는 자신들의 프로젝트에 이미 포함되어 있는 유니코드 비교 루틴을 오버로드해서 사용 할 수도 있습니다.
19. INSERT 가 너무나 느립니다. 초당 겨우 열 개 정도 INSERT 할 수 있습니다.
사실, SQLite 는 보통 컴퓨터에서 초당 50,000 개 이상의 Insert statement 를 거뜬히 처리합니다. 이 경우 초당 기껏해야 12 트렌젝션 정도가 발생합니다. 트렌젝션의 속도는 여러분의 디스크 회전속도에 따라서 다릅니다. 트렌젝션이 처리되려면 보통 디스크 플레터가 두번 정도 회전하면 됩니다. 7200RPM 디스크 드라이버는 초당 60번의 트렌젝션 처리가 가능합니다.
SQLite 에서는 트렌젝션을 처리하기 전에, 디스크 표면에 데이터가 정말로 안전하게 저장되었는지 확인합니다. 그렇기 때문에 트렌젝션 속도는 디스크 드라이버의 속도에 달려있습니다. 이 방식 덕분에, 시스템의 전원이 갑자기 나가거나, 운영체제가 충돌날 경우에도, 데이터는 안전합니다. 좀 더 자세한 설명을 보시려면 atomic commit in SQLite 를 읽어보시기 바랍니다.
기본 설정으로, 각각의 INSERT statement 는 고유한 트렌젝션을 가지고 있습니다. 하지만 BEGIN 과 COMMIT 을 이용하여 여러개의 INSERT statement 를 시도하면, 모든 inserts 는 하나의 트렌젝션으로 동작합니다. 각각의 insert statement 에 필요한 트렌젝션을 처리하는데 필요한 시간은 모두 하나로 합쳐지고, 소요되는 시간은 대폭적으로 감소됩니다.
또 다른 옵션은 PRAGMA synchronous=OFF 를 사용하는 것입니다. 이 명령은 SQLite 가 디스크에 데이터가 써 질때까지 기다리지 않도록 하여, 더 빨라지도록 합니다. 하지만 이 경우 갑자기 시스템 전원이 나가면 트렌젝션중에 있던 데이터는 손실될 수 있습니다.
20. 실수로 SQLite 데이타베이스에서 중요한 데이터를 지웠습니다. 복구 가능한가요?
만약 데이터베이스 파일을 백업해 두었다면, 데이터 복구가 가능합니다.
만약 백업을 하지 않은 경우에는 데이터 복구가 매우 어렵습니다. 데이터베이스 로우 파일(raw file)의 바이너리 덤프에서 문자열 데이터 일부분은 찾을 수 있을 것입니다. 수치 데이터는 특별한 툴을 사용하면 복원할 수 있겠지만, 그런 툴이 있는지는 모르겠습니다. SQLite 는 종종 삭제시 값을 0 으로 덮어쓰도록 SQLITE_SECURE_DELETE 옵션을 넣은 채로 컴파일 되기도 합니다. 이 경우에는 복구가 불가능합니다. 그리고 데이터를 삭제한 뒤에, VACUUM 을 수행했다면, 이 역시 복구가 불가능합니다. SQLITE_SECURE_DELETE 이나 VACUUM 을 하지 않은 상태에서는 데이터베이스 파일 의 미사용 영역 어딘가에 데이터가 남아 있을겁니다. 그러나 재차 말씀드리지만, 어떻게 데이터 복구를 해야 하는지에 대한 정확한 방법이나 툴은 존재하지 않습니다.
21. SQLITE_CORRUPT 에러가 무엇인가요? 데이타베이스가 "malformed" 되었다는게 무슨 의미인가요? 그리고 왜 발생하는건가요?
SQLITE_CORRUPT 에러는 SQLite 이 구조체(structure), 형식(format), 또는 데이터베이스 파일을 제어하는 어떤 요소들에서 에러를 발견했을 때, 발생합니다.
SQLite 는 정말 특이한 버그(DatabaseCorruption 참고)나 그 버그가 일반적으로 처리하기 어려운 경우가 아닌 이상, 데이터베이스 파일을 망가트리지 않습니다. 심지어 여러분의 프로그램에서 데이터베이스 update 도중에 오류가 발생하더라도, 데이터베이스 파일은 안전합니다. 데이터베이스는 여러분의 운영체제에서 오류가 발생하거나 전원이 갑자기 끊어지더라도 안전합니다. SQLite 의 충돌시 대처 방식은 다방면으로 연구되었고, 테스트 되었습니다. 그리고 실제로 수년간 수백만명의 사용자로부터 검증되었습니다.
다시 말해, 외부 프로그램이나 여러분의 하드웨어의 버그, 혹은 운영체제에 의해서 데이터베이스 파일이 손상될 경우는 몇가지 존재합니다. 자세한 내용은 automic commit 이나 locking 와 같은 SQLite 메일링 리스트에서 찾아 보실 수 있습니다.
CLI 를 사용해서 데이터베이스 파일로부터 스키마와 컨텐츠를 덤프(dump)한 뒤, 복구할 수 있는지는 데이터가 얼마나 심각하게 손상되었는지에 따라 다릅니다. 불행하게도 복구가 된다 하더라도, 일부 자잘한 데이터들은 복구가 되지 않을 수 있습니다.
22. SQLite 는 외래키(foreign keys)를 지원하나요?
3.6.19 버젼 이후부터 foreign key constraints 를 지원합니다.
SQLite 의 이전 버전은 외래키 제약 조건(foreign key constraints)를 해석하긴 하지만, 보장하지는 않습니다. 상응하는 기능은 SQLite 트리거를 이용하여 구현 가능합니다. 3.6.12 이후의 버젼에서 SQLite 쉘 도구에서 이러한 트리거를 자동으로 생성하는 ".genfkey" 명령을 지원합니다. 좀 더 자세한 정보를 원하시면 readme 를 읽어보시기 바랍니다.
23. SQLite 를 빌드할 때, 컴파일 옵션에 SQLITE_OMIT 를 사용하면 컴파일러에서 오류가 발생합니다.
컴파일 타임 옵션인 SQLITE_OMIT_... 은 원시 소스 파일을 빌드할 때만 동작합니다. SQLite amalgamation 이나 pre-processed 소스파일을 빌드할 때는 동작하지 않습니다.
미리 정해진 SQLITE_OMIT_... 옵션을 동작하게 하는 특수한 amalgamation 을 빌드하는 것은 가능합니다. 이런 동작에 대한 명령들은 SQLITE_OMIT ... 문서에 찾아 보실 수 있습니다.
24. WHERE 절에 column1="column1" 이 동작하지 않는 것 같습니다. 왜냐면 column1 의 값이 "column1" 인 행 뿐만 아니라, 테이블의 모든 행이 리턴되기 때문입니다.
SQL 에서 문자열을 감싸기 위해서는, 쌍따옴표(double-quotoes)대신 홑따옴표(single-quotes)를 사용해야 합니다. 이것이 SQL 표준 요구사항입니다. WHERE 절에서 사용할 때, column1='column2' 처럼 되어야 합니다.
SQL 은 특수 문자를 포함하거나 키워드가 되는 식별자(column 또는 table 이름) 를 감쌀 때, 따옴표(double-quotes)를 사용합니다. 즉 따옴표(double-quotes)는 식별자를 처리(escaping)하는 방법입니다. 그러므로 column1="column1" 의 의미는 column1=column1 을 의미하게 되고, 항상 true 를 리턴하게 됩니다.
25. SQLite 에서 생성하는 문법 다이어그램(syntax diagrams)은 어떤가요?
이 부분에 대해서는 http://wiki.tcl.tk/21708 에 잘 설명되어 있습니다.
26. SQL 표준에서는 컬럼에서 NULL 이 하나 또는 그 이상이더라도 UNIQUE 을 적용하도록 되어 있습니다. 하지만 SQLite 에는 그렇지 않는 것 같습니다. 버그인가요?
아마도 SQL92 에 있는 다음 내용을 말씀하시는 것 같군요.
unique 제약 조건은 한 테이블에서 unique 컬럼에 동일한 null 이 아닌 값을 갖는 행(row)가 존재할 수 없음을 나타냅니다.
이 문장은 모호합니다. 다음 두가지로 해석될 수 있습니다.
1. unique 제약 조건은 한 테이블에서 unique 컬럼에 동일한 값을 갖거나, null 값을 갖는 행(row)이 unique 컬럼에 들어갈 수 없음을 나타냅니다.
2. unique 제약 조건은 한 테이블에서 unique 컬럼에 null 이 아니면서, 값이 동일한 행이 존재할 수 없음을 나타냅니다.
SQLite 는 PostgreSQL, MySQL, Oracle, Firebird 와 같이 첫번째 해석을 따르고 있습니다. Infomix 나 Microsoft SQL Server 는 두번째 해석을 따르고 있긴 합니다. 하지만 SQLite 개발자는 첫번째 해석이 더 자연스럽고, 다른 대부분의 데이터베이스 엔진과 동일하게 동작하는게 맞다고 생각합니다. 그렇기 때문에 첫번째 해석처럼 동작하는 것입니다.
27. SQLite 의 Export Control Calssification Number(ECCN) 은 어떻게 되나요?
Commerce Control List(CCL)을 엄밀히 검토해 본 결과, 우리는 public-domain SQLite 소스코드의 코어(core)가 ECCN 을 따르지 않는다는 것을 확인했습니다. 그러므로 ECCN 은 EAR99 가 됩니다.
public-domain SQLite 코어에서는 그렇습니다. 만약 새로운 코드를 추가해서 SQLite 를 확장시키거나, 여러분의 프로그램에 SQLite 를 정적링크(statically link) 하는 특이한 경우에는 ECCN 이 변경될 수도 있습니다.
RECENT COMMENT