SQLite — не игрушка

    Рассказываю, почему SQLite отлично подойдет вам в повседневной работе. И неважно, разработчик вы, аналитик, тестировщик, админ или продакт-менеджер.

    Для затравки несколько известных фактов:

    • SQLite — самая распространенная СУБД в мире, включена во все популярные ОС.

    • Работает без сервера.

    • Для разработчиков — встраивается прямо в приложение.

    • Для всех остальных — удобная консоль (REPL) одним файлом (sqlite3.exe на Windows, sqlite3 в Linux / macOS).

    Консоль, импорт и экспорт

    Консоль — это киллер-фича SQLite: более мощный инструмент анализа данных, чем Excel, и сильно более простой, чем какой-нибудь pandas. Данные из CSV загружаются одной командой, таблица создается автоматически:

    > .import --csv city.csv city
    > select count(*) from city;
    1117

    Поддерживаются базовые SQL-фичи, а результат консоль показывает в приятной табличке. Продвинутые SQL-фичи тоже есть, но о них чуть позже.

    select
      century || '-й век' as dates,
      count(*) as city_count
    from history
    group by century
    order by century desc;
    ┌──────────┬────────────┐
    │  dates   │ city_count │
    ├──────────┼────────────┤
    │ 21-й век │ 1          │
    │ 20-й век │ 263        │
    │ 19-й век │ 189        │
    │ 18-й век │ 191        │
    │ 17-й век │ 137        │
    │ 16-й век │ 79         │
    │ 15-й век │ 39         │
    │ 14-й век │ 38         │
    │ 13-й век │ 27         │
    │ 12-й век │ 44         │
    │ 11-й век │ 8          │
    │ 10-й век │ 6          │
    │ 9-й век  │ 4          │
    │ 5-й век  │ 1          │
    │ 3-й век  │ 1          │
    └──────────┴────────────┘

    Куча форматов выгрузки данных: sql, csv, json, даже markdown и html. Все делается парой команд:

    .mode json
    .output city.json
    select city, foundation_year, timezone from city limit 10;
    .shell cat city.json
    [{"city":"Адыгейск","foundation_year":1969,"timezone":"UTC+3"},
    {"city":"Майкоп","foundation_year":1857,"timezone":"UTC+3"},
    {"city":"Горно-Алтайск","foundation_year":1830,"timezone":"UTC+7"},
    {"city":"Алейск","foundation_year":1913,"timezone":"UTC+7"},
    {"city":"Барнаул","foundation_year":1730,"timezone":"UTC+7"},
    {"city":"Белокуриха","foundation_year":1846,"timezone":"UTC+7"},
    {"city":"Бийск","foundation_year":1709,"timezone":"UTC+7"},
    {"city":"Горняк","foundation_year":1942,"timezone":"UTC+7"},
    {"city":"Заринск","foundation_year":1748,"timezone":"UTC+7"},
    {"city":"Змеиногорск","foundation_year":1736,"timezone":"UTC+7"}]

    Нативная работа с JSON

    Нет ничего удобнее SQLite для анализа и преобразования JSON. Можно селектить данные напрямую из файла, как будто это обычная таблица. Или загрузить в таблицу и селектить оттуда — как вам удобнее.

    select
      json_extract(value, '$.code') as code,
      json_extract(value, '$.name') as name,
      json_extract(value, '$.rate') as rate,
      json_extract(value, '$.default') as "default"
    from
      json_each(readfile('currency.sample.json'))
    ;
    ┌──────┬───────────────────┬────────────┬─────────┐
    │ code │       name        │    rate    │ default │
    ├──────┼───────────────────┼────────────┼─────────┤
    │ AZN  │ Манаты            │ 0.023107   │ 0       │
    │ BYR  │ Белорусские рубли │ 0.034966   │ 0       │
    │ EUR  │ Евро              │ 0.011138   │ 0       │
    │ GEL  │ Грузинский лари   │ 0.0344     │ 0       │
    │ KGS  │ Киргизский сом    │ 1.131738   │ 0       │
    │ KZT  │ Тенге             │ 5.699857   │ 0       │
    │ RUR  │ Рубли             │ 1.0        │ 1       │
    │ UAH  │ Гривны            │ 0.380539   │ 0       │
    │ USD  │ Доллары           │ 0.013601   │ 0       │
    │ UZS  │ Узбекский сум     │ 142.441417 │ 0       │
    └──────┴───────────────────┴────────────┴─────────┘

    Неважно, насколько развесистый JSON — можно выбрать атрибуты любой вложенности:

    select
      json_extract(value, '$.id') as id,
      json_extract(value, '$.name') as name
    from
      json_tree(readfile('industry.sample.json'))
    where
      path like '$[%].industries'
    ;
    ┌────────┬──────────────────────┐
    │   id   │         name         │
    ├────────┼──────────────────────┤
    │ 7.538  │ Интернет-провайдер   │
    │ 7.539  │ ИТ-консалтинг        │
    │ 7.540  │ Разработка ПО        │
    │ 9.399  │ Мобильная связь      │
    │ 9.400  │ Фиксированная связь  │
    │ 9.401  │ Оптоволоконная связь │
    │ 43.641 │ Аудит                │
    │ 43.646 │ Страхование          │
    │ 43.647 │ Банк                 │
    └────────┴──────────────────────┘

    CTE и операции над множествами

    Разумеется, поддерживаются Common Table Expressions (конструкция WITH) и джойны, тут даже примеры приводить не буду. А если данные иерархичные (таблица ссылается сама на себя через столбец вроде parent_id) — поможет рекурсивный WITH. Иерархию любого уровня можно «размотать» одним запросом.

    with recursive tmp(id, name, level) as (
      select id, name, 1 as level
      from area
      where parent_id is null
    
      union all
    
      select
        area.id,
        tmp.name || ', ' || area.name as name,
        tmp.level + 1 as level
      from area
        join tmp on area.parent_id = tmp.id
    )
    
    select * from tmp;
    ┌──────┬─────────────────────────────────────┬───────┐
    │  id  │               name                  │ level │
    ├──────┼─────────────────────────────────────┼───────┤
    │ 113  │ Россия                              │ 1     │
    │ 1    │ Россия, Москва                      │ 2     │
    │ 1586 │ Россия, Самарская область           │ 2     │
    │ 1588 │ Россия, Самарская область, Кинель   │ 3     │
    │ 78   │ Россия, Самарская область, Самара   │ 3     │
    │ 212  │ Россия, Самарская область, Тольятти │ 3     │
    │ ...  │ ...                                 │ ...   │
    └──────┴─────────────────────────────────────┴───────┘

    Множества? Нет проблем: UNION, INTERSECT, EXCEPT к вашим услугам.

    select employer_id
    from employer_area
    where area_id = 1
    
    except
    
    select employer_id
    from employer_area
    where area_id = 2;

    Хотите рассчитать один столбец на основании нескольких других? Пожалуйста — вычисляемые столбцы:

    alter table vacancy
    add column salary_net integer as (
      case when salary_gross = true then
        round(salary_from/1.13)
      else
        salary_from
      end
    );

    Вычисляемый столбец в селекте доступен точно так же, как обычный:

    select
      substr(name, 1, 40) as name,
      salary_net
    from vacancy
    where
      salary_currency = 'RUR'
      and salary_net is not null
    limit 10;
    ┌──────────────────────────────────────────┬────────────┐
    │                   name                   │ salary_net │
    ├──────────────────────────────────────────┼────────────┤
    │ Ведущий инженер-программист (Delphi)     │ 40000      │
    │ Ведущий программист Scala / Java ( Senio │ 60000      │
    │ Java / Kotlin Developer                  │ 150000     │
    │ Ведущий аналитик 1С                      │ 150000     │
    │ Разработчик C#                           │ 53097      │
    │ Программист 1С                           │ 80000      │
    │ Java - разработчик (Middle, Senior)      │ 100000     │
    │ Программист C#/ .NET                     │ 70796      │
    │ Тестировщик ПО/ QA engineer (ручное тест │ 45000      │
    │ Курьер                                   │ 17699      │
    └──────────────────────────────────────────┴────────────┘

    Мат. статистика

    Описательная статистика? Запросто: среднее, медиана, процентили, стандартное отклонение и вот это все. Правда, придется подключить библиотеку со стат. функциями, но это тоже одна команда (и один файл).

    .load sqlite3-stats
    
    select
      count(*) as book_count,
      cast(avg(num_pages) as integer) as mean,
      cast(median(num_pages) as integer) as median,
      mode(num_pages) as mode,
      percentile_90(num_pages) as p90,
      percentile_95(num_pages) as p95,
      percentile_99(num_pages) as p99
    from books;
    ┌────────────┬──────┬────────┬──────┬─────┬─────┬──────┐
    │ book_count │ mean │ median │ mode │ p90 │ p95 │ p99  │
    ├────────────┼──────┼────────┼──────┼─────┼─────┼──────┤
    │ 1483       │ 349  │ 295    │ 256  │ 640 │ 817 │ 1199 │
    └────────────┴──────┴────────┴──────┴─────┴─────┴──────┘

    Лирическое отступление. SQLite традиционно бедна функциями по сравнению с каким-нибудь постгресом. Но их легко добавить, чем многие и занимаются — каждый кто во что горазд. Получается легкий бардак.

    Поэтому я решил сделать нормальный набор библиотек, с разделением по предметной области и автоматической сборкой для всех ОС. Пока библиотек там немного, но скоро прибавится:

    sqlite-plus (GitHub)

    А вот еще о статистике. Можно нарисовать распределение значений прямо в консоли. Смотрите, какая милота:

    with slots as (
      select
        num_pages/100 as slot,
        count(*) as book_count
      from books
      group by slot
    ),
    max as (
      select max(book_count) as value
      from slots
    )
    select
      slot,
      book_count,
      printf('%.' || (book_count * 30 / max.value) || 'c', '*') as bar
    from slots, max
    order by slot;
    ┌──────┬────────────┬────────────────────────────────┐
    │ slot │ book_count │              bar               │
    ├──────┼────────────┼────────────────────────────────┤
    │ 0    │ 116        │ *********                      │
    │ 1    │ 254        │ ********************           │
    │ 2    │ 376        │ ****************************** │
    │ 3    │ 285        │ **********************         │
    │ 4    │ 184        │ **************                 │
    │ 5    │ 90         │ *******                        │
    │ 6    │ 54         │ ****                           │
    │ 7    │ 41         │ ***                            │
    │ 8    │ 31         │ **                             │
    │ 9    │ 15         │ *                              │
    │ 10   │ 11         │ *                              │
    │ 11   │ 12         │ *                              │
    │ 12   │ 2          │ *                              │
    │ 13   │ 5          │ *                              │
    │ 14   │ 3          │ *                              │
    │ 15   │ 1          │ *                              │
    │ 17   │ 1          │ *                              │
    │ 18   │ 2          │ *                              │
    └──────┴────────────┴────────────────────────────────┘

    Быстродействие

    SQLite спокойно работает с десятками миллионов записей (с сотнями тоже — я проверял). Обычные INSERT дают на моем ноуте около 240 тысяч записей в секунду. А если подключить исходный CSV как виртуальную таблицу (такая специальная фича) — еще в 2 раза быстрее.

    .load sqlite3-vsv
    create virtual table temp.blocks_csv using vsv(
        filename="ipblocks.csv",
        schema="create table x(network text, geoname_id integer, registered_country_geoname_id integer, represented_country_geoname_id integer, is_anonymous_proxy integer, is_satellite_provider integer, postal_code text, latitude real, longitude real, accuracy_radius integer)",
        columns=10,
        header=on,
        nulls=on
    );
    .timer on
    insert into blocks
    select * from blocks_csv;
    
    Run Time: real 5.176 user 4.716420 sys 0.403866
    select count(*) from blocks;
    3386629
    
    Run Time: real 0.095 user 0.021972 sys 0.063716

    Среди разработчиков распространено мнение, что SQLite не подходит для веба, потому что поддерживает только одного клиента. Это миф. В режиме write-ahead log (стандартная фича современных СУБД) читателей может быть сколько угодно. Писатель — один, но часто больше и не надо.

    SQLite отлично подходит для небольших сайтов и приложений. Например, sqlite.org использует SQLite в качестве базы, не заморачиваясь с оптимизацией (~200 запросов на страницу). При этом у него 700К визитов в месяц, а работает быстрее 95% сайтов.

    Документы, графы и поиск

    Поддерживаются частичные индексы и индексы по выражениям, как в «больших» СУБД. Можно даже строить индексы на виртуальных столбцах.

    Так SQLite можно превратить хоть в документную БД: хранить сырой json и строить индексы по json_extract() на нужных столбцах:

    create table currency(
      body text,
      code text as (json_extract(body, '$.code')),
      name text as (json_extract(body, '$.name'))
    );
    
    create index currency_code_idx on currency(code);
    
    insert into currency
    select value
    from json_each(readfile('currency.sample.json'));
    explain query plan
    select name from currency where code = 'RUR';
    
    QUERY PLAN
    `--SEARCH TABLE currency USING INDEX currency_code_idx (code=?)

    Можно и как графовую базу использовать. Тут уже придется либо злые WITH RECURSIVE использовать, либо добавить щепотку программирования:

    simple-graph (GitHub)

    Полнотекстовый поиск работает из коробки:

    create virtual table books_fts
    using fts5(title, author, publisher);
    
    insert into books_fts
    select title, author, publisher from books;
    
    select
      author,
      substr(title, 1, 30) as title,
      substr(publisher, 1, 10) as publisher
    from books_fts
    where books_fts match 'ann'
    limit 5;
    ┌─────────────────────┬────────────────────────────────┬────────────┐
    │       author        │             title              │ publisher  │
    ├─────────────────────┼────────────────────────────────┼────────────┤
    │ Ruby Ann Boxcar     │ Ruby Ann's Down Home Trailer P │ Citadel    │
    │ Ruby Ann Boxcar     │ Ruby Ann's Down Home Trailer P │ Citadel    │
    │ Lynne Ann DeSpelder │ The Last Dance: Encountering D │ McGraw-Hil │
    │ Daniel Defoe        │ Robinson Crusoe                │ Ann Arbor  │
    │ Ann Thwaite         │ Waiting for the Party: The Lif │ David R. G │
    └─────────────────────┴────────────────────────────────┴────────────┘

    А хотите in-memory базу для промежуточных вычислений? Одна строчка кода на питоне:

    db = sqlite3.connect(":memory:")

    Можно даже обращаться к ней из нескольких соединений:

    db = sqlite3.connect("file::memory:?cache=shared")

    И еще много всего

    Есть навороченные оконные функции (в точности как в PostgreSQL). UPSERT, UPDATE FROM и generate_series(). R-Tree индексы. Регекспы, fuzzy-поиск и гео. По фичам SQLite посоперничает с любой «взрослой» СУБД.

    Надеюсь, эта статья вдохновит вас применить SQLite в своих задачах. Спасибо, что прочитали!

    Если интересно, как использовать SQLite на полную — подписывайтесь на канал @sqliter

    Комментарии 88

      +7
      Использую эту базу данных в своих приложениях в качестве хранилища конфигурации (когда эта самая конфигурация достаточно сложная).
        +4
        А я использую в качестве файла проекта. Удобно добросить/удалить данные, сделать их выборку/сортировку по разным критериям, сохранить состояние программы и потом вернуться к какой-то длительной операции над данными спустя некоторое время (хоть на следующий день, хоть через 2 года).
        +8

        Бар проще посчитать через оконные функции, что-то вроде
        select count(*) over (partition by slot) / count(*) over ()

          +1

          Да, так тоже можно! Я взял этот пример кода из урока, который идет еще до изучения оконных функций. Поэтому он без них ツ

          +21
          SQLite очень хорош для временного хранения данных, потому что помогает обеспечить консистентность в случае аварийного завершения программы, поэтому используется в том числе как файл проекта в редакторах и даже сохранение в играх.

          По умолчанию SQLite работает в супер-надёжном, супер-медленном режиме. Если у вас нет цели обеспечить сохранность и целостность данных (это разные вещи, кстати, даже взаимно мешающиеся) при любом виде падения (программы, ОС, со стола) — разберитесь, как ускорять. Разница в скорости — в 10 000 раз, без преувеличения.

          Приятнее работать с SQLite не напрямую, а через ORM. Есть очень тонкие ORM, которые почти ничего не едят. Например Peewee. Есть несколько видов sqlite-dict, которые умеют только делать таблицу в 2 колонки и представлять её как словарь — но зачастую большего и не нужно. С другой стороны, есть навороченные ORM типа Django. Да, если кто не знал, можно из Django импортировать только ORM и использовать в своей программе, не имеющей никакого отношения к вебу.
            +4
            У меня больше чем в 3-10 раз (в зависимости от приложения) ускорить не удавалось :). Это даже если полностью отключать проверку консистентности.
              +8

              Мне тоже кажется, что 10000 — это художественное преувеличение ツ Вообще, если без экстрима, этих двух настроек должно быть достаточно:


              pragma journal_mode = WAL;
              pragma synchronous = normal;
                +1
                Да, я именно на них и остановился в production
                  0
                  Мне тоже кажется, что 10000 — это художественное преувеличение
                  Скорее всего, это если сравнивать самый худший и самый лучший вариант. Где самый худший — это добавления тысяч строк по одной без использования транзакций, при настройках на самом надежном и медленном режиме.
                  0
                  А вы файл на низкооборотный HDD положите, причём под Linux. Наверное мне мерещится, но то-ли хитрозадая Винда научилась игнорировать избыточные sync-и, то ли в виндовом SQLite дефолты другие.
                    +1
                    но то-ли хитрозадая Винда научилась игнорировать избыточные sync-и

                    Да, чтото с syncом они сделали. У меня на win 10 из под WSL какие то нереальные цифры теста производительности fsync у пг получаются
                  0
                  Есть несколько видов sqlite-dict, которые умеют только делать таблицу в 2 колонки и представлять её как словарь — но зачастую большего и не нужно.
                  Естественно. И это для 95% задач хватает даже с избытком. Однако же тогда зачем этот скюлайт-словарь?)) Обычных программных словарей опять же хватает для таких задач. Автор там где-то пишет, что почитал он или что-то вписал куда-то и у него оно АЖ 240тыщ вроде записей в секунду составило. Извините, но заполнение/чтение/вставки в программные словари — это миллионы «записей» в секунду, обычное дело. Я про то что программные штатные средства работают на порядок быстрее (даже в шарпе).

                  п.с.: Как бы я не использовал все эти бд даже узкозаточенные — один фиг всегда перехожу на самописный код, ибо да, оно как минимум на порядок быстрее работает, чудес не бывает.
                  п.п.с.: Понятное дело что самописное годится не всем и не всегда, но тем не менее как оно и было написано кем то тут — все эти бд — это игрушки…
                    +3
                    Вы действительно сообщаете нам, что словарь с дупликацией на диск и составлением индекса для всех значений, будет медленнее чем просто dict() на операции добавления? Даже не знаю, что ответить. Ну да?
                    0

                    Спасибо тебе, добрый человек!


                    sqlitedict прямо то, что доктор прописал, похоже, для своих проектов самое оно (и не только).


                    Плюс еще там можно и запросы выполнять, а учитывая нативную поддержку json, все вообще замечательно :)

                    +5

                    Я в основном использую SQLite для прикладного анализа данных. Загрузить датасет из csv / json, найти проблемы в данных, почистить данные, сджойнить таблички, пофильтровать, сгруппировать, посчитать агрегаты, выгрузить обратно в csv — как-то так.


                    Удобно, что в большинстве случаев не приходится даже ничего писать на Python. SQL, как декларативный язык, созданный специально для обработки данных — компактнее и проще, чем скрипты.


                    Еще использую SQLite как базу для блога. Работает быстро, удобный бекап — закоммитил один файл в гитхаб и готово.

                      +1
                      Интересный сценарий (насчет анализа данных). То есть вы прямо в консоли пишете запросы и там же получаете результат? Получается, вместо pandas и т.д?
                        0

                        Да, именно! Получается быстрее и удобнее пандаса. Конечно, пандас мощнее, но мощь его редко когда требуется. SQLite прекрасно справляется в большинстве случаев.

                        +1

                        Интересное использование, спасибо за статью. Не знал о такой возможности.
                        У меня периодически возникает такая необходимость, я обычно открываю CSV в экселе-там тоже очень удобно делать фильтры, группировки, аггрегаты, но попробовал бы вариаинт с SQL

                          0

                          Эксель прекрасный инструмент, ни в коем случае не хочу как-то его принизить. Но вот нормально работать в нем с несколькими связанными таблицами — совсем не получается.


                          В целом, «SQLite против Excel» чем-то схоже с «командная строка против проводника». Безусловно, сложнее. Но если освоить — удобнее, мощнее и продуктивнее для большого класса задач.

                            0

                            Я бы еще поспорил кто сложнее, по-моему excel это та бездна которую до конца изучить невозможно.
                            Я как раз хочу попробовать решение автора потому что SQL сам по себе проще и более знаком мне, а в экселе слоожные сценарии мне надо либо гуглить либо обходится тем что знаю и делать больше руками.
                            Например я сходу не помню как легко аггрегировать данные с нескольких листов, хотя и видел это.
                            Я разбивал джсон на колонки, делал поиск по вложенным полям-но сейчас хоть убей не вспомню как-если понадобится буду опять гуглить.

                          0
                          Подскажите, а использовать Power Query для этого не удобнее? Или SQLite есть какие-то плюсы по сравнению с профильным инструментом от Microsoft? Будет забавно, если не совсем профильный инструмент работает лучше чем специализированный.
                            +3

                            Для меня Power Query — это еще один навороченный доменный язык для работы с данными. Осваивать его совершенно не хочется, потому для работы с данными уже придумали SQL, который поддерживается всеми современными СУБД.


                            Визуально, конечно Power Query круче консоли SQLite. Но если вместо консоли использовать Apache Superset или Metabase — получится еще круче.

                              0
                              В принципе я и имел в виду визуальные средства работы. Большинство операций можно делать вообще без кода. В командной строке точно так не выйдет ) Вот подумал, что раз кому-то удобнее командная строка, значит там должны быть весомые плюшки.
                              0

                              Плюсы будут когда количество строк будет ближе к 10 млн и потребует очень большого числа джоинов. В остальных случаях плюсов скорее всего не будет. Но все зависит от ситуации и потребности.

                              0
                              Подскажите, что за движок такой у блога? Статьи в markdown пишутся, или что-то визуальное?
                                0

                                Использую Ghost, это движок с UI. Он по умолчанию предлагает MySQL, но можно поставить на SQLite, что я и сделал.

                                0

                                Здравствуйте. А можно подробнее про решение для блога? Это какой-то движок для блогов или статический генератор сайтов? И что именно коммитится? Некий патч в бд, маркдаун статьи или что-то третье? Вообщем, интересна и эта прикладная часть использования СУБД! Заранее спасибо за ответ.

                                0

                                Кстати кто-то имеет опыт SQLite и LiteDB? Ну то есть может их сравнить по собственному опыту и примерно рассказать плюсы-минусы?

                                  +3
                                  А вы сейчас про какой LiteDB? Дотнетовский, который никуда не прикрутишь, или питоновский, который медленнее, чем хранить данные в JSON?
                                    0

                                    Дотнетовский.

                                      0
                                      Так его никуда не прикрутишь:)
                                        0

                                        В дотнет прикрутишь :)


                                        Вопрос стоит ли.

                                    +1

                                    Используем LiteDB в своём проекте уже несколько лет (около 15 тыс установок у клиентов, довольно небольшая нагрузка, порядка 1 rps вида «прочитать состояние из бд, внести изменения, сохранить назад обновлённую версию», размер базы порядка 10-100мб).
                                    Мигрировали с LocalDb, во время миграции сравнивали с SQLite по производительности/удобству.
                                    Основной плюс — работает очень быстро. Как мы не тюнили SQLite — litedb из коробки обгонял его по нашему workflow работы (без изменения основной логики приложения) в разы. Оба они на порядок обгоняли localdb.
                                    Главный минус — я бы не назвал litedb production-ready. Периодически всплывают баги, приводящие к нарушению структуры базы и делающие её нечитаемой. Уже по-моему третья «мажорная» версия вышла которая обещает что вот теперь то мы их все исправили, но на нашей клиентской Бахе все равно раз в пару месяцев у кого-нибудь что-то ломается. В другом use-case где мы используем её чисто как кеш (под достаточно объемные данные часто изменяющиеся) — у неё течёт размер и раз в несколько месяцев приходится руками сносить Файлы, потому что размер бд вырастает до десятка Гб.
                                    Своя структура работы, нет поддержки популярными Orm, нет транзакций (по крайней мере когда мы её выбирали, потом их добавили, потом отказались, в общем политика меняется от версии к версии).


                                    В целом — для собирания Proof of concept проекта с последующей переделкой, или под данные которые если что не жалко потерять или можно восстановить из других источников — очень удобно. Настраивается быстро, работа интуитивная, все летает. Но как полноценную единствннную БД в серьезном проекте — я бы не стал использовать.

                                      0

                                      Ок, спасибо. Мы её думали именно для кэша и может быть для сеттингов использовать.

                                        0
                                        Embedded NoSQL database for .NET
                                        An open source MongoDB-like database with zero configuration — mobile ready

                                        по-моему описание с www.litedb.org/ говорит само за себя.
                                        Из плюсов — доступно в исходниках.
                                      0
                                      Еще можно добавить SQLCipher
                                        0
                                        … и rqlite
                                          0

                                          Жаль, что невозможно параллельно писать данные (из разных коннектов).

                                            +1
                                            Отнюдь. Составьте менеджер очереди, и пусть он принимает записи отовсюду и пишет их по очереди, заодно там же энкапсулируете весь SQL и приоритеты настроите.
                                              +3

                                              Вот так с помощью нехитрых инструментов можно построить SQL сервер из буханки хлеба ;)

                                                +3
                                                Да, но сия нехитрая конструкция займёт две страницы кода и использует только компоненты стандартной библиотеки, что само по себе в некоторых случаях является огромным плюсом.
                                                  0
                                                  «Но зачем?» (ц)
                                            +1

                                            Частенько использую sqlite для in-memory хранилища, когда нужно делать множественные выборки данных по нескольким полям.

                                              +8

                                              Рассказываю, почему игрушка (для кто не в курске):


                                              bash-5.1$ sqlite3 test.sqlite
                                              -- Loading resources from /Users/justhabrausr/.sqliterc
                                              SQLite version 3.28.0 2019-04-15 14:49:49
                                              Enter ".help" for usage hints.
                                              sqlite> CREATE TABLE abc (icol INTEGER);
                                              sqlite> INSERT INTO abc (icol) VALUES ("tratata");
                                              sqlite> SELECT * FROM abc;
                                              tratata
                                              sqlite> .quit
                                              bash-5.1$ 

                                              Так что не всё то лапочка, что солнышко.

                                                +4
                                                Вон в C (язык программирования) тоже можно напрямую в память писать (невзирая на тип данных) и выстрелить себе в ногу, а то и в голову. И никто не считает его игрушкой из-за этого.
                                                  +1

                                                  Я, видимо, что-то пропустил.
                                                  Покажите как одной строчкой C записать напрямую в память невзирая на тип данных.
                                                  Без предупреждений компилятора и runtime error. Как в примере с SQLite.
                                                  PS. это не к тому, чтобы сравнивать С и SQLite (занятие довольно бестолковое непрактичное), а чисто по-женски интересно стало.

                                                    +7
                                                    memcpy с приведением источника и приёмника к void?
                                                      –1
                                                      1. man memcpy: "Функция memcpy() копирует n байтов..." (AKA uint8_t).
                                                      2. В постановке задачи — не "с приведением к void", а "невзирая".

                                                      "Не прокатило..." ©

                                                        0
                                                        void * memcpy(void *dst, const void *src, size_t len); (man memcpy (freebsd 12.1))
                                                        байт в данном случае выступает как минимальная единица длины данных, а не как тип данных. SQLite тоже не позволяет мне 3 бита в память записать.
                                                        П.С. байт это не обязательно 8 бит, поэтому, если упарываться дальше, то можно вводить и всякое типа uint7_t =)
                                                    0

                                                    Но многие считают, что использовать С для чего-то серьезного поэтому нельзя. Некоторые даже из-за этого новые языки создают.

                                                      0

                                                      Я может открою Вам тайну, но всё серьёзное в мире написано на С. Даже некоторые новые языки ;)

                                                        +4

                                                        Rust (претендующий на ту же нишу) давно уже self-hosted, какой-нибудь там хаскель — ещё более давно.
                                                        Всё серьёзное, чем вы пользуетесь в ежедневной жизни, имеет, как минимум, достаточно значимую примесь ++ — хром или FF, как минимум.

                                                    +5

                                                    Да, в плане типов SQLite — это своеобразный JavaScript. Если для кого-то это проблема, можно просто не использовать такую «динамическую типизацию». Используйте The Good Parts ツ

                                                      +5
                                                      Нельзя. То есть можно, но баги никто не отменял. Рано или поздно вы напутаете порядок полей в каком-нибудь инсерте. А чем раньше ошибка обнаружена, тем меньше от нее вреда. В идеале на этапе статического анализа кода.
                                                      0
                                                      можно поставить крайне не информативный чекер CHECK(icol+1 > icol)
                                                        0
                                                        Полностью поддерживаю. Меня в приложении выморозила еще более тупая фишечка (на Android): если поле таблицы строка и туда вставить строку только с цыфрами, то на выходе — ошибка парсинга при попытке получить это поле как строку. Это просто шутка на первое апреля а не БД, но выбор нет
                                                          +6
                                                          это точно не sqlite а та библиотека через которую работаете с базой
                                                            +1
                                                            Есть выбор, это же джава, write once run anywhere.
                                                          +4
                                                          Добавлю что еще sqlite используется в не очень известной но очень функциональной системе контроля версий Fossil
                                                          Все хранилище в ней представлено в виде одного файла (БД SQLite) и при этом есть тикет система (веб интерфейс), запускается также из одного исполнимого файла.
                                                            +2

                                                            Что характерно, Фоссил написан тем же самым автором — Ричардом Хиппом. Интересный дядька вообще.

                                                              0
                                                              Система контроля версий Monotone тоже использует SQLite.
                                                              0

                                                              @threadreaderapp unroll


                                                              P.S. Спасибо за тред

                                                                0

                                                                Пожалуйста! Прикольный сервис, но потерял все картинки. Да и в целом формат твит-шторма — на любителя.

                                                                +4
                                                                Всем советую sqlite для разных применений, отличная база

                                                                С удивлением (на самом деле нет, когда не читаешь всю документацию так бывает) узнал кучу нового, и про динамическую типизацию из комментов, и про with recursive,…
                                                                Хабр торт.

                                                                Можно даже обращаться к ней из нескольких соединений:
                                                                db = sqlite3.connect(«file::memory:?cache=shared»)
                                                                К сожалению только в пределах одного процесса, т.е. shared не имеет особого смысла и сомнительный юзкейс
                                                                  +2

                                                                  Мне особенно нравится, что последние годы разработчики SQLite часто сознательно реализуют фичи точно так же, как сделано в PostgreSQL. Например, оконные функции сделаны именно так, и даже тестировались на постгресе. Кажется, такая унификация с лучшей опенсорсной реляционной СУБД — отличная идея.


                                                                  К сожалению только в пределах одного процесса, т.е. shared не имеет особого смысла и сомнительный юзкейс

                                                                  Почему сомнительный, разве он не подходит для async-операций в пределах одного процесса?

                                                                  +2

                                                                  Для меня существенным минусом стало отсутствие case insensitive для non ASCII символов. Интересно, не собираются ли добавить функцию?

                                                                    +4

                                                                    Она есть, но придется отдельно компилировать SQLite с поддержкой Unicode (SQLITE_ENABLE_ICU).

                                                                      +1
                                                                      Есть небольшое расширение (это копия; оригинал вроде как уже не доступен), которое работает в большинстве случаев, в том числе и для русского языка. Актуально для Windows, где для SQLITE_ENABLE_ICU надо тащить большую библиотеку, а это не всегда хочется.
                                                                    0

                                                                    Там какие-то дикие непонятки с sequence. Почему-то автор sqlite с недетской серьёзностью воспринимает автоинкременты, которые работают только в простейших случаях

                                                                      +5
                                                                      Мне почему то статья напомнила времена (которые я не застал, но что-то о них читал), когда проповедовалось, что SQL — это вообще язык не для программистов, а для простых пользователей, ведь каждый может научиться писать такие простые команды и получать нужные ему результаты. Пропаганда, говорят, была очень активной, но безрезультатной — опыт использования показал, что даже такой язык — это слишком сложно для простого пользователя, не специализирующегося в IT.
                                                                      Нет, общий вывод — что не стоит пренебрегать SQLite как рабочим инструментом — я поддерживаю, это действительно удобная система для некоторых вариантов использования.
                                                                      Но, безусловно, не стоит пытаться воспринимать её как silver bullet, и пытаться встроить во все возможные и невозможные места.
                                                                      Лично я, скорее, для части описанных в статье задач воспользуюсь Excel как более универсальным и простым инструментом, для других — более сложных — возьму более привычный мне SQL Server, благо у него тоже есть бесплатная версия, пусть чуть более сложная в первоначальной настройке, зато более привычная и удобная мне лично.
                                                                        +4

                                                                        Прошу прощения за минус, хотел поставить плюс, но промахнулся на мобиле, а отменить непонятно как :(

                                                                          +4

                                                                          На мой взгляд основное преимущество SQLite не в том что он бесплатный, а в том что это библиотека, а не отдельное приложение/сервер.

                                                                            0
                                                                            у mysql есть библиотека libmysqld причем очень давно, но мне кажется ее использовать сильно сложнее
                                                                          0
                                                                          Спасибо, очень информативно
                                                                            +2
                                                                            Однажды, выкинул домашний сайт на joomla и переписал на чистом js + 10 строк php и sqlite. Выглядит также, занимает все вместе килобайт 100 (или 200 с картинками).
                                                                              0
                                                                              > .import --csv city.csv city

                                                                              и с какой версии sqlite в import появился ключ --csv?
                                                                                0
                                                                                3.32.0. Поиск здесь по --csv
                                                                                  0

                                                                                  Можно и без него:


                                                                                  .mode csv
                                                                                  .import city.csv city
                                                                                  0

                                                                                  недавно заметил что некоторые проекты на .net core зачем-то подгружают sqlite. не знаю зачем

                                                                                    0

                                                                                    Могут например настройки свои в нём хранят. Сейчас так многие делают. И не только на .net core.


                                                                                    Firefox например вроде бы куки и букмарки в нём хранил. По крайней мере раньше.

                                                                                      0
                                                                                      спасибо! мне тоже показалось что это чтото инфраструктурное для самой среды разработки или вспомогательных систем
                                                                                        0
                                                                                        Firefox например вроде бы куки и букмарки в нём хранил. По крайней мере раньше.

                                                                                        Целую груду всякой всячины хранит, включая кэш.

                                                                                          –2
                                                                                          Как и хром, как и сафари
                                                                                      +3
                                                                                      SQLite отлично подойдет вам в повседневной работе

                                                                                      Полностью согласен. Именно SQLite помог создать удостоверяющий центр CAFL63.

                                                                                        0
                                                                                        Поэтому я решил сделать нормальный набор библиотек, с разделением по предметной области и автоматической сборкой для всех ОС. Пока библиотек там немного, но скоро прибавится:

                                                                                        так значить, дело и было не в хорошести SQLite))
                                                                                          0
                                                                                          У меня sqlite используется в моём приложении ReadRss, который сделан в виде расширения для браузеров.

                                                                                          Работает отлично в Chrome, Firefox, старой Opera, мобильном Kiwi

                                                                                          База 4 Гига — всё летает.
                                                                                            0
                                                                                            Ссылка? Ибо расширений с названием ReadRss не находится.

                                                                                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                                                          Самое читаемое