Pull to refresh

odbm = объектная обёртка для key-value хранилищ

Reading time2 min
Views1.4K

odbm



Оптимизация проекта => оптимизация хранилища => dbm => dict style => :-( => odmb => :-)



Бэкенды

  • tokyo cabinet (через tokyo-python) — всячески рекомендую, в пару раз быстрее аналогов, файл бд компактнее
  • kyoto cabinet (через родную обёртку) — от авторов tokyo-cabinet и по их описанию круче, но по моим тестам тормознее в 2-3 раза
  • gdbm
  • fsdbm — удобна для хранения крупных документов
  • … пишите, если чего-то не хватает

    Установка

    pip install odbm

    репа: bitbucket

    Синтаксис


    from datetime import datetime, date
    import odbm
    
    # описываем модель
    class User(odbm.Model):
        username    = odbm.UnicodeProperty(primary_key=True)
        birthday    = odbm.DateProperty(key='b')
        is_active   = odbm.Property(key='a', default=True)
        is_admin    = odbm.Property(key='r', default=False)
        created     = odbm.DateTimeProperty(key='c')
        
         __filename__    = 'var/user.odbm.tch'
         __db_type__     = 'tc'    
    
    
    # создаём и сохраняем объект
    User(username='fizban', birthday=date(1917, 1, 1), created=datetime.now()).save()
    # в dict-style получится следующее:
    # db['fizban'] = {'b': timestamp даты, 'c': timestamp времени}
    # обратите внимание на сокращение ключей (см. key=... в property)
    
    # получаем объект по ключу
    u = User.get('fizban')
    print u.birthday  # datetime.date(1917, 1, 1)
    
    # изменяем объект
    u.is_active = False
    u.save()
    
    # создадим ещё объекы
    for i in xrange(10):
        User(username=('test-%i' % i), birthday=date(1950 + i, 1, 1)).save()
    
    # все объекты
    User.find()
    
    # получим все объекты c birthday > 1955, отсортированные по username
    for obj in User.find(
            filter  = lambda u: u.birthday.year > 1955,
            order   = lambda u: u.username):
        print obj
    
    # количество объектов по условию
    print User.count(lambda u: u.username.startswith('f')) # 1
    
    # удаление объекта
    print User.count() # 11
    User.find_one().delete()
    print User.count() # 10
    
    


    Property

    • odbm.Property() — сюда можно пихать любые маршализируемые типы (например, {'a': [True, 1, None]})
    • odbm.UnicodeProperty() — для unicode строк, чтобы исключить путаницу с латинскими ascii и unicode ключами
    • odbm.DateTimeProperty() — datetime.datetime
    • odbm.DateProperty() — datetime.date
    • odbm.CompressedProperty() — как odbm.Property, но сжимается
    • odbm.CompressedUnicodeProperty — как odbm.UnicodeProperty, но сжимается


    Производительность

    Для теста запишем и считаем в случайном порядке 10к User-ов вышеописаной модели. И сравним с записью/чтением этих же данных в виде cPickle-нных словарей:

    seconds to write/read 10000 rows
    pickle (write, read): (1.0030829906463623, 0.25429201126098633)
    odbm (write, read): (0.99477910995483398, 0.14065694808959961)
    pickle file size: 2768704
    odbm file size: 1348752


    Уменьшение размера файла достигнуто за счёт описанного выше уменьшения длины ключей. Код теста тут.

    [offtop] О принципиальной важности компактности файла бд


    С год назад мы провели ряд тестов, которые ясно показали: независимо от движка субд, как только используемые файлы не помещаются в кеш файловой системы, скорость рандомных выборок падает на пару порядков. Если кому-то интересны цифры, вот всё что осталось от тех тестов:
Tags:
Hubs:
Total votes 25: ↑20 and ↓5+15
Comments19

Articles