Мой вопрос приходит непосредственно от this один, хотя меня интересует только ОБНОВЛЕНИЕ и только это.Повысить производительность SQLite в UPDATE-секунду?
У меня есть приложение, написанное на C/C++
, что делает интенсивное использование SQLite
, в основном SELECT/UPDATE
, на очень частый интервал (около 20 запросов каждый от 0,5 до 1 секунду)
Моя база данных не является большой, о записей в моменты, здесь структура таблицы:
CREATE TABLE player (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(64) UNIQUE,
stats VARBINARY,
rules VARBINARY
);
до этого момента я не использовал transactions
, потому что я улучшал код и хотел удар ловкость.
Тогда я измерил производительность базы данных, просто выполняя 10 update
запросы, следующие (в цикле различных значений):
// 10 times execution of this
UPDATE player SET stats = ? WHERE (name = ?)
где stats
является JSON ровно 150 символов и name
от 5-10 персонажи.
Без операций, результат неприемлем: - около 1 полной второго (0,096 каждого)
С сделками, время падает раз x7.5: - около 0,11 - 0,16 секунды (0,013 каждого)
Я попытался удалить большую часть базы данных и/или переупорядочить/удалить столбцы, чтобы увидеть, что это что-то изменило, но это не так. Я получаю вышеуказанные числа, даже если база данных содержит только 100 записей (проверено).
Затем я попытался играть с PRAGMA
вариантов:
PRAGMA synchronous = NORMAL
PRAGMA journal_mode = MEMORY
дал мне меньшие времена, но не всегда, больше как около 0,08 - 0,14 секунды
PRAGMA synchronous = OFF
PRAGMA journal_mode = MEMORY
Наконец дали мне чрезвычайно малые времена около 0,002 - 0,003 секунды, но я не хочу использовать его, так как мое приложение сохраняет базу данных каждую секунду, и есть высокая вероятность повреждения базы данных o n ОС/сбой питания.
Мой C SQLite
код для запросов является: (комментарии/обработка ошибок/несвязанные части опущенные)
// start transaction
sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, NULL);
// query
sqlite3_stmt *statement = NULL;
int out = sqlite3_prepare_v2(query.c_str(), -1, &statement, NULL);
// bindings
for(size_t x = 0, sz = bindings.size(); x < sz; x++) {
out = sqlite3_bind_text(statement, x+1, bindings[x].text_value.c_str(), bindings[x].text_value.size(), SQLITE_TRANSIENT);
...
}
// execute
out = sqlite3_step(statement);
if (out != SQLITE_OK) {
// should finalize the query no mind the error
if (statement != NULL) {
sqlite3_finalize(statement);
}
}
// end the transaction
sqlite3_exec(db, "END TRANSACTION", NULL, NULL, NULL);
Как вы видите, это довольно типичный TABLE
, записывает число невелико, и я делаю простой простой UPDATE
ровно 10 раз. Есть ли что-нибудь еще, что я мог бы сделать, чтобы уменьшить мои UPDATE
раз? Я использую последние SQLite 3.16.2
.
Примечание: Таймингов выше, поступающие непосредственно из одного
END TRANSACTION
запроса.Запросы выполняются в простой транзакции, а я - с использованием подготовленного оператора.
UPDATE:
Я выполнил некоторые тесты с транзакцией включенными и выключенными и различными обновлениями сосчитать. Я провел тесты со следующими параметрами:
VACUUM;
PRAGMA synchronous = NORMAL; -- def: FULL
PRAGMA journal_mode = WAL; -- def: DELETE
PRAGMA page_size = 4096; -- def: 1024
Результаты не вытекает:
Сделок (10 обновлений)
- 0,30800 сек (0.0308 на обновление)
- 0,30200 ИКС
- 0,36200 secs
- 0.28600 s ЭКС
Сделок (100 обновлений)
- 2.64400 сек (0.02644 каждое обновление)
- 2.61200 ИКС
- 2.76400 секунд
- 2.68700 секунд
нет транзакций Дополнения (1000 обновлений)
- 28.02800 сек (0.028 каждое обновление)
- 27.73700 сек
- ..
с транзакциями (10 обновлений)
- 0,12800 secs (0,0128 каждое обновление)
- 0,08100 сек
- 0.16400 ИКС
- 0,10400 сек
с транзакциями (100 обновлений)
- 0.088 секунд (0.00088 каждое обновление)
- 0,091 сек
- 0.052 Секунд
- 0.101 СЕК
с транзакциями (1000 обновлений)
- 0.08900 сек (0.000089 каждое обновление)
- 0.15000 ИКС
- 0.11000 секунд
- 0.09100 секунд
Мои выводы заключаются в том, что с transactions
нет смысла в time cost per query
. Возможно, времена становятся больше с колоссальным количеством обновлений, но меня не интересуют эти цифры. Там буквально нет разницы во времени между 10 и 1000 обновлений по одной транзакции. Однако мне интересно, является ли это аппаратным ограничением на моей машине и не может многое сделать. Кажется, я не могу пойти ниже ~100
miliseconds, используя единую транзакцию и варьируя 10-1000 обновлений, даже используя WAL.
Без транзакций фиксированная стоимость около 0.025
секунд.
Если вы используете languiage C/C++, используйте правильный тег. В противном случае это похоже на C++, а не на ** другой ** язык C! И это не сайт для проверки кода. – Olaf
@Olaf, единственный материал '' C++ '' 'std :: string'; остальное - 'C'. Я специально подчеркиваю это выше. Во-вторых, я не хочу, чтобы кто-то просматривал мой код, мне нужен лучший подход SQLite для решения моей проблемы. – user6096479
Он делает ** не ** компилируется как C, поэтому это не C. Просто потому, что у вас такой же синтаксис/грамматика не означает, что у вас есть одна и та же семантика! Тот, кто говорит вам, что C++ - это «C с классами», является неправильным и не знает, по крайней мере, одного из них достаточно хорошо, чтобы написать нетривиальный код. – Olaf