ãããŸã§ã®ç§ã®ãæ°ã«å
¥ãã®ãããã¯ã®2ã€ã¯ãSQLiteãšããŒããªã¥ãŒããŒã¿ããŒã¹ã§ãã ãããŠä»åã¯ãäž¡æ¹ã«ã€ããŠäžåºŠã«æžããŸãããã®æçš¿ã¯ãSQLite 4ã§äœ¿çšããã
LSMããŒã¹ã®ããŒå€ã¹ãã¬ãŒãžã®Pythonã©ãããŒã«æ§ããããŠããŸãã
ç§ã¯SQLiteã®ãªãªãŒã¹ã«ããŸãå³å¯ã«ã¯åŸããŸããããããŒãžã§ã³3.8.11ãç§ã®æ³šæãåŒããŸããããã®èšè¿°ã¯3.8.0ãšæ¯èŒããŠããã©ãŒãã³ã¹ã倧å¹
ã«åäžãããšäž»åŒµããŠããããã§ãã ä»éããæ
å ±ã§ããã«ããã¹ãæ€çŽ¢ã®ããã®æ°ããå®éšçãªæ¡åŒµæ©èœã«ã€ããŠã®èšåã«åºããããŸããïŒ
ããã«ã€ããŠã¯ãã€ãŠæžããŸãã ïŒããã®ããã
SQLite 4ã®ç¶æ³ã¯ã©ããªã£ãŠããã®ã§ããããã
å
¥æå¯èœãªæ
å ±ãæ€èšããçµæãéçºè
ã®ã¿ã¹ã¯ã®1ã€ã¯ãæ°ããããŒãžã§ã³ã®
ãã©ã°ã€ã³ããŒã¿ããŒã¹ãšã³ãžã³ã«
ã€ã³ã¿ãŒãã§ã€ã¹ãæäŸããããšã§ããããšã«æ°ä»ããŸããã ãã®æçš¿ã®å·çæç¹ã§ãSQLite 4ã«ã¯ãã§ã«2ã€ã®çµã¿èŸŒã¿ã®ããã¯ãšã³ããããããã®ãã¡ã®1ã€ã¯LSMããŒã¹ã®ããŒãšå€ã®ã¹ãã¬ãŒãžã§ãã éå»2ãæéã
UnQLiteãš
Vedisã®
çµã¿èŸŒã¿ kvãªããžããªçšã®Pythonã©ãããŒãæžã
ãŠããéã«
Cythonã§
éãã§ã
ãŸãã ã ãããŠãCythonã䜿çšããŠãSQLite 4ã§äœ¿çšãããLSMããŒã¹ã®ããŒã¿ããŒã¹ãšã³ãžã³ã€ã³ã¿ãŒãã§ã€ã¹ãäœæãããšè¯ããšæããŸããã
SQLite 4ãš
å°ããªLSMããããŒãã¡ã€ã«ã®
ãœãŒã¹ã³ãŒããç解ããã®ã§ã
python-lsm-db ïŒ
ããã¥ã¡ã³ã ïŒãæžããŸããã
LSMããªãŒãšã¯äœã§ããïŒ
çè«ãç解ããŠããéããLSMããªãŒã¯æ¬¡ã®ãã®ã§æ§æãããŠããŸãã
- ãããã¡ãšããŠæ©èœããã¡ã¢ãªããªãŒ
- ãã£ã¹ã¯äžã«ãã1ã€ä»¥äžã®æ°žç¶ããªãŒã
é åèªLSMã®æåMã¯ããŒãžãè¡šããŸããããã¯ããããã¡ãªã³ã°ãããã¬ã³ãŒãããã£ã¹ã¯äžã®ããªãŒãšçµåããæäœã§ãã ãã®æé ã«ããããã£ã¹ã¯äžã®ã·ãŒã¯ã®ã³ã¹ãã倧å¹
ã«åæžã§ããŸããããã¯ãé«éèšé²ãšãã1ã€ã®ããšãæå³ããŸãã äžæ¹ãã·ã¹ãã ã¯è€æ°ã®ããªãŒãæ€çŽ¢ãããããã©ã³ãã èªã¿åãã¯é
ããªãå ŽåããããŸãã ãŸããLSMããªãŒã¯ãåçã®BããªãŒ
ããã
é·ããªãå ŽåããããŸãã LSMããªãŒã®ãã1ã€ã®å©ç¹ã¯ãä¿åãããããŒã¿ã®æçåãå°ãªããªããããŒç¯å²ã®èªã¿åããé«éã«ãªãããšã§ãã
ããäžåºŠåŒ·èª¿ããŸããããã¯çè«ã«å¯Ÿããç§ã®ç解ã§ãã äœããã®æ¹æ³ã§èª€è§£ãããããéèŠãªãã€ã³ããèŠéãããããå¯èœæ§ããããŸãã
ããããã£
SQLite 4ã®LSMå®è£
ã«ã¯ãéåžžã«èå³æ·±ãããããã£ãããã€ããããŸãã
- ã¢ããªã±ãŒã·ã§ã³ã§äœ¿çšãããåã蟌ã¿DBã
- ã«ãŒãœã«ã䜿çšããŠããŒã衚瀺ããé åºãèšå®ããŸãã
- ãã©ã³ã¶ã¯ã·ã§ã³ïŒãã¹ãããããã©ã³ã¶ã¯ã·ã§ã³ãå«ãïŒã
- ã·ã³ã°ã«æžã蟌ã¿/ãã«ãèªã¿åãããµããŒãããMVCCããŒã¹ã®ãã©ã³ã¶ã¯ã·ã§ã³äžŠååã¢ãã«ã
- ãã£ã¹ã¯äžã«åäžã®ãã¡ã€ã«ãšããŠä¿åãããŠããããŒã¿ããŒã¹ã
- ã¢ããªã±ãŒã·ã§ã³ãŸãã¯é»æºé害æã®ããŒã¿åŸ©å
åã
- ããŒãºã«åãããŠæè»ã«ã«ã¹ã¿ãã€ãºããæ©èœã
Pythonã©ã€ãã©ãªã®äœæ
ããã§ã¯å§ããŸãããã ãŸããvirtualenvãäœæããpipã䜿çšããŠCythonãšlsm-dbãã€ã³ã¹ããŒã«ããŸãã
$ virtualenv test_lsm $ cd test_lsm $ source bin/activate (test_lsm) $ pip install Cython lsm-db
ã€ã³ã¹ããŒã«ã確èªããã«ã¯ã次ã®è¡ãå®è¡ã§ããŸãã
(test_lsm) $ python -c "import lsm, tempfile; lsm.LSM(tempfile.mktemp())"
ãã¹ãŠãã€ã³ã¹ããŒã«ãããæ£åžžã«åäœããŠããå Žåããã®ã³ãã³ãã®å®è¡ã«ã¯äœã䌎ããŸããã ããããLinuxã®Python 2.7ã§ã®ã¿ãã¹ãããããšã«çæããŠãã ããã ãããã£ãŠãWindowsã§Python 3.4ã䜿çšããŠããå Žåããã®ã³ãŒãããããã°ããå¿
èŠããããŸãã
äœè«
以äžã¯ãlsm-dbã©ã€ãã©ãªã®äž»ãªæ©èœãåæ ãã察話åã³ã³ãœãŒã«ã»ãã·ã§ã³ã®äŸã§ãã
APIããã¥ã¡ã³ãã«ã¯ãã¯ã©ã¹ãã¡ãœãããããã³ãã©ã¡ãŒã¿ãŒãšæ»ãå€ã®èª¬æã®å®å
šãªãªã¹ããå«ãŸããŠããŸãã
ãŸããä»®æ³ç°å¢ã§Pythonã€ã³ã¿ãŒããªã¿ãŒãèµ·åããããŒã¿ããŒã¹ãã¡ã€ã«ãžã®ãã¹ãæå®ããŠãLSMãªããžã§ã¯ãã®ã€ã³ã¹ã¿ã³ã¹ãäœæããŸãã
>>> from lsm import LSM >>> db = LSM('test.ldb')
LSMã¯ã©ã¹ã«ã¯ããã¡ã€ã«åã®ã»ãã«ãèšå®å¯èœãª
ãã©ã¡ãŒã¿ãŒ ïŒãããã¯ãµã€ãºãããŒãžãµã€ãºãªã©ïŒã
ããã€ããããŸã ã
ããŒããªã¥ãŒæ©èœ
SQLite 4 LSMãšã³ãžã³ã¯ããŒ/å€ã¹ãã¢ã§ãããPythonã®dictãªããžã§ã¯ãã«å€å°äŒŒãŠããŸãã dict-like APIã䜿çšããŸãã
>>> db['foo'] = 'bar' >>> print db['foo'] bar >>> for i in range(4): ... db['k%s' % i] = str(i) ... >>> 'k3' in db True >>> 'k4' in db False >>> del db['k3'] >>> db['k3'] Traceback (most recent call last): File "<stdin>", line 1, in <module> File "lsm.pyx", line 973, in lsm.LSM.__getitem__ (lsm.c:7142) File "lsm.pyx", line 777, in lsm.LSM.fetch (lsm.c:5756) File "lsm.pyx", line 778, in lsm.LSM.fetch (lsm.c:5679) File "lsm.pyx", line 1289, in lsm.Cursor.seek (lsm.c:12122) File "lsm.pyx", line 1311, in lsm.Cursor.seek (lsm.c:12008) KeyError: 'k3'
泚ïŒåé€ãããã°ããã®ããŒã«ã¢ã¯ã»ã¹ããããšãããšãKeyErrorãããã«ãããã¢ããããŸããã ããã©ã«ãã§ã¯ãããŒãæ€çŽ¢ãããšããã©ã€ãã©ãªã¯æåã«å®å
šã«äžèŽãããã®ãæ¢ããŸãã SQLite 4ã§ã¯ãæ¢ããŠããå€ãååšããªãå ŽåãLSMã¯æãè¿ãããŒãèŸæžçã«æ€çŽ¢ããããšãã§ããŸãã äžèŽããæ€çŽ¢ã«å ããŠã次ã«è¿ãããŒãè¿ãæ€çŽ¢ã¡ãœãããããã«2ã€ãããŸãïŒSEEK_LEãšSEEK_GEã å®å
šã«äžèŽãããã®ãèŠã€ãããªãå ŽåãSEEK_LEã¯ããŒã®æäžéšïŒæé«ã®ããŒïŒãè¿ããŸãããã®å€ã¯æ€çŽ¢ããå°ãããSEEK_GE-ããŒã®æäœïŒæäœã®ããŒïŒã¯å€ãæ€çŽ¢ããã倧ããã§ãã k1.5ãååšããªããšä»®å®ããŸãã
>>> from lsm import SEEK_LE, SEEK_GE >>>
ãããã«å ããŠãLSMã¯ãããŒïŒïŒãå€ïŒïŒãããã³æŽæ°ïŒïŒãªã©ãä»ã®å€ãã®ã¡ãœããããµããŒãããŠããŸãã
ã¹ã©ã€ã¹ãšå埩
SQLite 4 LSMã§ã¯ãããŒã¿ãçŽæ¥å埩åŠçããããããŒã®ãµãã»ãããéžæã§ããŸãã èå³æ·±ãç¹ã¯ãããŒã®ç¯å²ãèŠæ±ãããšããã®éå§ãšçµäºãååšããªãå¯èœæ§ãããããšã§ãã ããã€ãã®ããŒãæ¬ èœããŠããå ŽåãããŒã¿ããŒã¹ã¯æ¬¡ã®ã¯ããŒãºããŒïŒnext-closest keyïŒãèŠã€ããããã«ã·ãŒã¯ã¡ãœããã®1ã€ã䜿çšããŸãã
>>> [item for item in db] [('foo', 'bar'), ('k0', '0'), ('k1', '1'), ('k2', '2')] >>> db['k0':'k99'] <generator object at 0x7f2ae93072f8> >>> list(db['k0':'k99']) [('k0', '0'), ('k1', '1'), ('k2', '2')]
ç¹å®ã®æ¹åã®ãã¹ãŠã®ããŒãè¿ãã«ã¯ããªãŒãã³ãšã³ãã¹ã©ã€ã¹ã䜿çšã§ããŸãã
>>> list(db['k0':]) [('k0', '0'), ('k1', '1'), ('k2', '2')] >>> list(db[:'k1']) [('foo', 'bar'), ('k0', '0'), ('k1', '1')]
äžéãŸãã¯äžéãããŒã®ç¯å²å€ã®å Žåã空ã®ãªã¹ããè¿ãããŸãã
>>> list(db[:'aaa']) [] >>> list(db['z':]) []
ããŒãéã®é åºã§ååŸããã«ã¯ãã¹ã©ã€ã¹ã®æåã®ãã©ã¡ãŒã¿ãŒãšããŠäžçªäžã®ããŒãæå®ããã ãã§ãã éããŠããã¹ã©ã€ã¹ãæœåºããå Žåã¯ãã¹ããããã©ã¡ãŒã¿ãŒãšããŠTrueãæå®ã§ããŸãã
>>> list(db['k1':'aaa'])
ã·ãŒã¯ã¡ãœããã®æäœã®è©³çŽ°ã«ã€ããŠã¯ã
LSM.fetch_rangeïŒïŒã®ããã¥ã¡ã³ããã芧ãã ããã
ã«ãŒãœã«
ã»ãšãã©ã®å Žåãã¹ã©ã€ã¹ã§ååã§ãããã¬ã³ãŒããæ€çŽ¢ããã³è¡šç€ºããããã»ã¹ããã现ããå¶åŸ¡ããå¿
èŠãããå ŽåããããŸãã
>>> with db.cursor() as cursor: ... for key, value in cursor: ... print key, '=>', value ... foo => bar k0 => 0 >>> db.update({'k1': '1', 'k2': '2', 'k3': '3'}) >>> with db.cursor() as cursor: ... cursor.first() ... print cursor.key() ... cursor.last() ... print cursor.key() ... cursor.previous() ... print cursor.key() ... foo k3 k2 >>> with db.cursor() as cursor: ... cursor.seek('k0', SEEK_GE) ... print list(cursor.fetch_until('k99')) ... [('k0', '0'), ('k1', '1'), ('k2', '2'), ('k3', '3')]
ã«ãŒãœã«ã䜿çšãããšãã¯ãéãããŸãŸã«ããªãã§ãã ããã æåã«ãã«ãŒãœã«ãéããã®ã«åœ¹ç«ã€LSM.cursorïŒïŒã³ã³ããã¹ããããŒãžã£ãŒã䜿çšã§ããŸãã
ååŒ
SQLite 4 LSMããŒã¿ããŒã¹ã¯ããã¹ãããããã©ã³ã¶ã¯ã·ã§ã³ããµããŒãããŸãã ãããã䜿çšããæãç°¡åãªæ¹æ³ã¯ãã³ã³ããã¹ããããŒãžã£ãŒãŸãã¯ãã³ã¬ãŒã¿ãŒãšããŠãæ©èœããLSM.transactionïŒïŒã¡ãœããã䜿çšããããšã§ãã
>>> with db.transaction() as txn: ... db['k1'] = '1-mod' ... with db.transaction() as txn2: ... db['k2'] = '2-mod' ... txn2.rollback() ... True >>> print db['k1'], db['k2'] 1-mod 2
ã©ããããããããã¯ã䜿çšããŠãã©ã³ã¶ã¯ã·ã§ã³ãéšåçã«ã³ããããŸãã¯ããŒã«ããã¯ããããšãã§ããæ°ãããã©ã³ã¶ã¯ã·ã§ã³ã¯å€ãå Žæããéå§ãããŸãã
>>> with db.transaction() as txn: ... db['k1'] = 'outer txn' ... txn.commit()
å¿
èŠã«å¿ããŠãLSM.beginïŒïŒãLSM.commitïŒïŒãLSM.rollbackïŒïŒãæ瀺çã«åŒã³åºãããšãã§ããŸãã
>>> db.begin() >>> db['foo'] = 'baze' >>> print db['foo'] baze >>> db.rollback() True >>> print db['foo'] bar
æ§èœ
ããããã¹ãŠã®ãã³ãããŒã¯ã«èããããšã¯ã§ããŸããããLSMããŒã¿ããŒã¹ã®ããã©ãŒãã³ã¹ã«éåžžã«èå³ããããŸããã ãããã£ãŠã
å°ããªãã³ãããŒã¯ã䜿çšããŠãSQLite 4 LSMãšLevelDBãBerkeley DBãKyoto Cabinet
ãæ¯èŒããŸããã è¯ãæ¹æ³ã§ã¯ãKyoto CabinetãšBerkeley DBã¯ãã«ãã€ã³BããªãŒã§ãããKyoto CabinetãšLevelDBã¯ããŒã¿ããŒã¹ãžã®ããã»ã¹ã®è€æ°ã¢ã¯ã»ã¹ããµããŒãããŠããªããããããããæ¯èŒã§ããŸããã§ããã ãŸããLevelDBã«ãã©ã³ã¶ã¯ã·ã§ã³ãµããŒãããããã©ãããããããŸããã ãšãããããã³ãããŒã¯ã¯ããŒã¿ããŒã¹ã©ã€ãã©ãªãçŽæ¥äœ¿çšãããå©çšå¯èœãªPythonãã©ã€ããŒã䜿çšããŸãã ãã®ãããçµæã¯Pythonã©ã€ãã©ãªã®ããã€ãã®å¶éãšæ©èœã®åœ±é¿ãåããå¯èœæ§ããããŸãã
ãã³ãããŒã¯çµæïŒå°ãªãã»ã©è¯ãïŒïŒ
Testing with N = 100000 ------------------------------------ BDBBTree ~~~~~~~~ Writes: 0.469 Reads: 0.479 Range (10%): 0.212 Range (20%): 0.192 Range (40%): 0.185 Range (80%): 0.186 KyotoBTree ~~~~~~~~~~ Writes: 0.208 Reads: 0.203 Range (10%): 0.219 Range (20%): 0.188 Range (40%): 0.188 Range (80%): 0.187 LevelDB ~~~~~~~ Writes: 0.227 Reads: 0.225 Range (10%): 0.031 Range (20%): 0.027 Range (40%): 0.028 Range (80%): 0.027 LSM ~~~ Writes: 0.282 Reads: 0.239 Range (10%): 0.059 Range (20%): 0.052 Range (40%): 0.052 Range (80%): 0.052
ãã®ããŒã¿ã次ã®ããã«è§£éããŸããããŒç¯å²ãååŸããéã®ããŒã¯ã¬ãŒDBãšäº¬éœå
é£ã®ããã©ãŒãã³ã¹ã¯ãéåžžã«æåŸ
ãããŠããããšãå€æããŸããã ãŸããLevelDBãšLSMã¯ãéã«ãç¯å²ãèªã¿åããšãã«ã¯ããã«é«éã§ããããšãå€æããéåžžã«é«éã«æžã蟌ã¿ãŸãã
LevelDBã¯SQLite 4 LSMãããåªããŠããŸããããåŸè
ã®èªã¿åãç¯å²ã¯BããªãŒãããã¯ããã«é«éã§ãã 圌ã®èªæžã¯å·çã®4åé
ãããšãå€æãããããLSMãã³ãããŒã¯ã販売ããå¿
èŠããããŸãã æåã¯èªã¿åãã«åé¡ããããšæã£ãŠããŸãããããã¹ãŠããã§ããããšã«Pythonã«ãŒãœã«ã©ãããŒã«ããããšã«æ°ä»ããŸããïŒïŒã Pythonã³ãŒããCèšèªAPIã®çŽæ¥åŒã³åºãã«çœ®ãæããåŸãèªã¿åãé床ã倧å¹
ã«åäžããŸããã Python LSMãã€ã³ããŒãè©ŠããŠã¿ããå Žåã¯ãããŒãžã§ã³0.1.4以éã䜿çšããŠããããšã確èªããŠãã ããã以åã®ããŒãžã§ã³ã§ã¯fetchïŒïŒã®å®è£
ãéåžžã«é
ãããã§ãã
SQLite 4ã«é¢ãã泚æ
SQLite 4ãèªåã§ãã«ãããå Žåã¯ãå€ããªããžããªãè€è£œããŠã³ã³ãã€ã«ã§ããŸãã
$ fossil clone http://www.sqlite.org/src4/ sqlite4.fossil $ mkdir sqlite4-build $ cd sqlite4-build $ fossil open ../sqlite4.fossil $ ln -s Makefile.linux-gcc Makefile $ export CFLAGS="$CFLAGS -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_COLUMN_METADATA=1 -DSQLITE_ENABLE_UNLOCK_NOTIFY -DSQLITE_SECURE_DELETE $ make
å®äºãããšããã€ããªãã¡ã€ã«sqlite4ãlibsqlite4.aããã³sqlite4.hãäœæãããŸãã
ãŸããåã蟌ã¿ããã»ã¹ãç°¡çŽ åããããã«ãå
ã®çµåãã¡ã€ã«ã®ç¬èªã®ã³ããŒãäœæã§ããŸãã
make sqlite4.c
ãŸããSQLite 4 ...ã®çŸåšã®ã¹ããŒã¿ã¹ãäžæã§ããããšã«ã泚æããå¿
èŠããããŸãã Hippå士ã¯ãSQLite 3ã®ãµããŒããç¶ç¶ããäºå®ã§ãããšè¿°ã¹ãŸããã ãããããšã³ããŠãŒã¶ãŒã®ä»£ããã«ã4çªç®ã®ããŒãžã§ã³ãè©ŠããŠã¿ãŸãã ããããæªæ¥ã¯åœŒå¥³ã«ããããäºå®ã§ã¯ãªãã ããšãããã ãšããŠããããã¯çŸåšã®åœ¢ã§ã¯ãªããããããŸããã
è¿œå è³æ
æ±ãã詳现ãå¿
èŠãªå Žåã圹ç«ã€ãªã³ã¯ã®ãªã¹ãã以äžã«ç€ºããŸãã
ããªãã奜ããããããªãç§ã®ä»ã®æçš¿ïŒ
ä»ã®çµã¿èŸŒã¿NoSQLããŒã¿ããŒã¹ã«èå³ãããå Žåã¯ã
unqlite-pythonããã³
vedis-pythonã«æ³šæããŠ
ãã ãã ã ãããã¯ããããMongoDBãšRedisã«éåžžã«äŒŒãŠãããã©ãããŒãCã®è»œéæ¡åŒµæ©èœã䜿çšããPythonãããžã§ã¯ãã«åã蟌ãããšãã§ããŸãã