Подскажите, почему может медленно выполняться запрос вида "UPDATE table1 SET field1 = %d WHERE rowid = %d"
Для таблицы в 1000 записей это занимает около 200 мс и на порядки больше чем время остальных запросов. Куда смотреть, что проверить?
Здравствуйте, MasterZiv, Вы писали:
MZ>Вообще-то 200 милисекунд -- вполне хорошее время выполнения запроса. MZ>Секунды -- уже много (для такого запроса), а вот так -- очень даже хорошо.
Нет, для такой маленькой таблицы это много даже в случае перебора всех записей. rowid как я понимаю, это типа primary key, и должно происходить обращение по индексу. Если я меняю запрос на аналогичный "UPDATE table1 SET field1 = %d WHERE field2 = %s", то время выполнения 2 мс (есть индекс по field2). Это что, глюк SQLite или я что-то не понимаю?
Здравствуйте, algol, Вы писали:
A>Подскажите, почему может медленно выполняться запрос вида "UPDATE table1 SET field1 = %d WHERE rowid = %d" A>Для таблицы в 1000 записей это занимает около 200 мс и на порядки больше чем время остальных запросов. Куда смотреть, что проверить?
Индексы там есть? время может на перестройку индекса уходить
Шурыгин Сергей
"Не следует преумножать сущности сверх необходимости" (с) Оккам
Здравствуйте, Sshur, Вы писали:
A>>Подскажите, почему может медленно выполняться запрос вида "UPDATE table1 SET field1 = %d WHERE rowid = %d" S>Индексы там есть? время может на перестройку индекса уходить
Здравствуйте, algol, Вы писали:
a> Подскажите, почему может медленно выполняться запрос вида "UPDATE table1 SET field1 = %d WHERE rowid = %d" a> Для таблицы в 1000 записей это занимает около 200 мс и на порядки больше чем время остальных запросов. Куда смотреть, что проверить?
А DDL таблички и конкретные тестовые значения можно посмотреть?
On 20.12.2010 17:46, algol wrote:
> Нет, для такой маленькой таблицы это много даже в случае перебора всех записей. > rowid как я понимаю, это типа primary key, и должно происходить обращение по
Это примерно время записи на диск+накладуха от самой СУБД. Если ты не согласен,
обоснуй, почему тебе кажется, что это много. Не на пальцах, а в цифрах.
Здравствуйте, algol, Вы писали:
A>Подскажите, почему может медленно выполняться запрос вида "UPDATE table1 SET field1 = %d WHERE rowid = %d" A>Для таблицы в 1000 записей это занимает около 200 мс и на порядки больше чем время остальных запросов. Куда смотреть, что проверить?
Здравствуйте, Anton Batenev, Вы писали:
AB>А DDL таблички и конкретные тестовые значения можно посмотреть?
Все очень просто:
CREATE TABLE files (path text, ext text, curver int)
CREATE INDEX IF NOT EXISTS path_idx ON files(path)
CREATE INDEX IF NOT EXISTS ext_idx ON files(ext)
path и ext — путь к файлу и расширение соответственно, path уникален. curver — это rowid другой таблицы.
Медленно исполняемый запрос:
UPDATE files SET curver = %d WHERE rowid = %d
Идентичный запрос выполняется почти в 100 раз быстрее:
UPDATE files SET curver = %d WHERE path = '%s'
Еще одна деталь — обновляемая запись обычно добавляется непосредственно перед обновлением.
Здравствуйте, MasterZiv, Вы писали:
MZ>Это примерно время записи на диск+накладуха от самой СУБД. Если ты не согласен, MZ>обоснуй, почему тебе кажется, что это много. Не на пальцах, а в цифрах.
200ms — многовато для времени записи на диск, если учесть, что seek time у современных дисков где-то 5-10ms
Здравствуйте, algol, Вы писали:
A>Все очень просто: A>
A>CREATE TABLE files (path text, ext text, curver int)
A>CREATE INDEX IF NOT EXISTS path_idx ON files(path)
A>CREATE INDEX IF NOT EXISTS ext_idx ON files(ext)
A>
A>path и ext — путь к файлу и расширение соответственно, path уникален. curver — это rowid другой таблицы.
A>Медленно исполняемый запрос: A>UPDATE files SET curver = %d WHERE rowid = %d A>Идентичный запрос выполняется почти в 100 раз быстрее: A>UPDATE files SET curver = %d WHERE path = '%s' A>Еще одна деталь — обновляемая запись обычно добавляется непосредственно перед обновлением.
Это очень похоже на баг. Ибо в документации явно написано, что выборка по rowid должна быть вдвое быстрее, чем по руками созданному индексу PRIMARY KEY. Здесь же все наоборот. Этот вопрос лучше задать на форуме поддержки sqlite.
Здравствуйте, algol, Вы писали:
a> Медленно исполняемый запрос: a> UPDATE files SET curver = %d WHERE rowid = %d a> Идентичный запрос выполняется почти в 100 раз быстрее: a> UPDATE files SET curver = %d WHERE path = '%s' a> Еще одна деталь — обновляемая запись обычно добавляется непосредственно перед обновлением.
Есть совершенно глупое предположение — а в случае второго запроса path стоит существующий в таблице или нет? Потому как я набросал быстрый тест — если path существует, то время запроса в два раза больше, чем с rowid и сопоставимо с 200ms (у меня 100ms), а вот если нет, то вставки не производится и оно реально отрабатывает в 100 раз быстрее.
P.S. 100ms для SQLite нормальное время, т.к. журнал транзакций, блокировки и все дела.
Здравствуйте, Anton Batenev, Вы писали:
AB>P.S. 100ms для SQLite нормальное время, т.к. журнал транзакций, блокировки и все дела.
Это не нормальное время, принимая во внимание данные, приведенные автором по скорости аналогичного update, с выборкой не по кластерному индексу (который в случае SQLite есть rowid), а по обычному. Не может быть так. Ибо разница, очевидно, только в поиске.
Здравствуйте, Anton Batenev, Вы писали:
AB>Есть совершенно глупое предположение — а в случае второго запроса path стоит существующий в таблице или нет? Потому как я набросал быстрый тест — если path существует, то время запроса в два раза больше, чем с rowid и сопоставимо с 200ms (у меня 100ms), а вот если нет, то вставки не производится и оно реально отрабатывает в 100 раз быстрее.
По идее, оба запроса должны быть совершенно идентичны и обновлять ровно одну запись. rowid в первом запросе указывает на запись с path, указанным во втором запросе. Но это надо проверить, возможно там баг, тогда это все объясняет.
AB>P.S. 100ms для SQLite нормальное время, т.к. журнал транзакций, блокировки и все дела.
Операции выполняются в цикле, все закешировано. А 100мс — это 10 апдейтов в секунду. Это слишком медленно для миниатюрной таблицы и не стыкуется с данными по призводительности SQLite (http://www.sqlite.org/speed.html). Например 25000 updates в транзакции занимают 3,5 сек (0,14 мс на запись), 1000 INSERT без транзакции — 13 сек (13 мс на запись).
Ну, и по моим замерам INSERT в ту же таблицу отрабатывает за 5-10мс.
Здравствуйте, Gaperton, Вы писали:
G> AB>P.S. 100ms для SQLite нормальное время, т.к. журнал транзакций, блокировки и все дела. G> Это не нормальное время, принимая во внимание данные, приведенные автором по скорости аналогичного update, с выборкой не по кластерному индексу (который в случае SQLite есть rowid), а по обычному. Не может быть так. Ибо разница, очевидно, только в поиске.
В сообщении рядом я написал, что 100ms — это время, скажем так, одной атомарной операции изменения данных. И так же отдельно отметил, что в случае, если данные не меняются (т.е. под условие WHERE не попадает ни одной записи при обновлении), то скорость резко повышается, т.к. базе не требуется синхронизировать данные с файловой системой ибо они не менялись. А вот что у автора в WHERE вопрос пока открытый.
Что же касается тезиса о том, что выборка по кластерному индексу будет быстрее нежели по обычному, то я с ним полностью согласен — где-то в два раза, но на фоне операции синхронизации с ФС это может быть заметно только на больших объемах (ну или на скорости SELECT-ов).
Здравствуйте, algol, Вы писали:
a> По идее, оба запроса должны быть совершенно идентичны и обновлять ровно одну запись. rowid в первом запросе указывает на запись с path, указанным во втором запросе. Но это надо проверить, возможно там баг, тогда это все объясняет.
Ждемс.
a> Операции выполняются в цикле, все закешировано. А 100мс — это 10 апдейтов в секунду. Это слишком медленно для миниатюрной таблицы и не стыкуется с данными по призводительности SQLite (http://www.sqlite.org/speed.html). Например 25000 updates в транзакции занимают 3,5 сек (0,14 мс на запись), 1000 INSERT без транзакции — 13 сек (13 мс на запись).
Я попробовал написать простой тест (по аналогии тестов по ссылке):
* вставка 100 записей без оборачивания в транзакцию (каждая запись суть транзакция): ~7000 ms (70 ms / запись)
* вставка 100 записей в одну транзакцию: ~150 ms (1.5 ms / запись)
* обновление одной записи в таблице 100 раз (каждое обновление суть транзакция): ~7500 ms (75 ms / запись)
* обновление 100 записей в таблице в одной транзакции: ~100 ms (1 ms / запись)
Т.е. соотношения между транзакция/не транзакция приблизительно сохраняются. Но тут надо учесть, что там тесты для SQLite 2.x, а у меня 3.x, а так же немного другое оборудование (в частности, далеко не шустрый винт). Если же провести тесты на обычном сервере с FreeBSD и нешифрованным UFS2, то там вставка 1000 записей без транзакции укладывается в те же 13 сек, а вот обновление в транзакции уже ~0.02ms / запись.
Т.о. следует известное правило при работе с SQLite — делать запросы на вставку / обновление пачками, которые обернуты в транзакции. Дополнительно можно сделать небольшие читы типа:
PRAGMA page_size = 32768;
P.S. И заметь — даже работая в транзакции все равно нахожусь где-то в минимальном пределе 100 ms — скорее всего это минимальное время для всяких блокировок, fsync-ов и прочего.
Здравствуйте, algol, Вы писали:
A>Для таблицы в 1000 записей это занимает около 200 мс и на порядки больше чем время остальных запросов. Куда смотреть, что проверить?
Транзакция открыта? ...А то у SQLite есть такой эффект, что при авто-коммите оно тормозит...
__________
16.There is no cause so right that one cannot find a fool following it.
Здравствуйте, Anton Batenev, Вы писали:
a>> По идее, оба запроса должны быть совершенно идентичны и обновлять ровно одну запись. rowid в первом запросе указывает на запись с path, указанным во втором запросе. Но это надо проверить, возможно там баг, тогда это все объясняет. AB>Ждемс.
Да, ваше предположение подтвердилось. Дествительно при втором запросе фактически обновления не было. Это объясняет разницу во времени.
Но 200 мс на UPDATE — это слишком много, время нужно как-то уменьшать в разы.
AB>P.S. И заметь — даже работая в транзакции все равно нахожусь где-то в минимальном пределе 100 ms — скорее всего это минимальное время для всяких блокировок, fsync-ов и прочего.
Что-то не сходится. У меня INSERT в 2 таблицы в одной транзакции занимает 15-20 мс. На этом фоне 200 мс на обновление одного поля как-то не смотрится.