|
книжки по Sqlite на русском языке..
|
|||
---|---|---|---|
#18+
1. Картинка как называется? Если SQLite lock transitions, то у меня она внизу стр. 187. ИМХО автор нафантазировал немного про PENDING. В цепочке UNLOCKED->PENDING->SHARED лишний PENDING, т.к. зачем ужесточать блокировку, если потом опять понизить? В документации про нее просто написано: Блокировка PENDING означает, что процесс, содержащий блокировку, хочет как можно скорее записать в базу данных и просто ждет, пока все текущие блокировки SHARED будут освобождены, чтобы он мог получить блокировку EXCLUSIVE. Никакие новые блокировки SHARED не допускаются к базе данных, если активна блокировка PENDING, хотя существующие блокировки SHARED продолжают работать. В русском варианте уже есть п. 5.3.3. про блокировки, перечитай, может поможет. 2. Замечаний нет. 3. На меня ссылаться никак не надо, анонимность важнее. ... |
|||
:
Нравится:
Не нравится:
|
|||
25.07.2018, 14:30 |
|
книжки по Sqlite на русском языке..
|
|||
---|---|---|---|
#18+
Там же в документации нет ничего про UNLOCKED->PENDING->SHARED 5.0 Запись в файл базы данныхЧтобы записать в базу данных, процесс должен сначала получить блокировку SHARED, как описано выше (возможно, откат неполных изменений, если есть горячий журнал). После того, как получена SHARED, необходимо получить блокировку RESERVED. Блокировка RESERVED сигнализирует, что процесс намеревается записать в базу данных в какой-то момент в будущем. Только один процесс за один раз может удерживать блокировку RESERVED. Но другие процессы могут продолжать читать базу данных, пока удерживается блокировка RESERVED. Если процесс, который хочет писать, не может получить блокировку RESERVED, это должно означать, что другой процесс уже имеет блокировку RESERVED. В этом случае попытка записи не удалась и возвращает SQLITE_BUSY. ... ... |
|||
:
Нравится:
Не нравится:
|
|||
25.07.2018, 14:48 |
|
книжки по Sqlite на русском языке..
|
|||
---|---|---|---|
#18+
... |
|||
:
Нравится:
Не нравится:
|
|||
26.07.2018, 00:06 |
|
книжки по Sqlite на русском языке..
|
|||
---|---|---|---|
#18+
... |
|||
:
Нравится:
Не нравится:
|
|||
26.07.2018, 00:06 |
|
книжки по Sqlite на русском языке..
|
|||
---|---|---|---|
#18+
Dima T1. Картинка как называется? Если SQLite lock transitions, то у меня она внизу стр. 187. у тебя таки третье издание? ... |
|||
:
Нравится:
Не нравится:
|
|||
26.07.2018, 00:16 |
|
книжки по Sqlite на русском языке..
|
|||
---|---|---|---|
#18+
tchingizDima T1. Картинка как называется? Если SQLite lock transitions, то у меня она внизу стр. 187. у тебя таки третье издание? Не знаю, там не написано. Но картинка та самая, которую ты показал. ... |
|||
:
Нравится:
Не нравится:
|
|||
26.07.2018, 07:31 |
|
книжки по Sqlite на русском языке..
|
|||
---|---|---|---|
#18+
.;-----555 .;3 Lock States .3 Состояния Блокировок .^ В большинестве случаев продолжительность блокировки приближается к продолжительности транзакции. Хотя они начинаются раздельно, они всегда заканчиваются вместе. При завершении транзакции, освобождается связанная с ней блокировка. Другими словами, блокировка не заканчивается до тех пор, пока не завершается её транзакция или не сбойнет приложение. И, после краха приложения или системы, транзакция не завершается, в этом случае в БД остается неявная блокировка с которой начнет работу следующее соединение. Эту тема уточняется позднее в секции 'Блокировки и Восстановление После Краха'. .^ В \nm существует пять различных состояний блокировок и соединение не зависимо от того, чем оно занимается, всегда находится в одном из них. Транзакции и состояния блокировок \nm изображены на рис. .;+pic6-3 . Рисунок раскрывает каждое возможное состояние блокировки, в которое может попадать транзакция равно как и путь, которым транзакция может попасть в это состояние на протяжении своей жизни. Рисунок изображен в терминах состояний блокировок, блокировок транзакций и жизненного цикла транзакций. На рисунке действительно можно проследить жизнь транзакции в терминах блокировок. .b .;- \begin {figure}[h] \includegraphics[width=1.00\textwidth]{./m6_pics/f140_1.png} \includegraphics[width=1.00\textwidth]{./m6_pics/f140_2.png} \caption{Состояние блокировок в транзакциях SQLite}\label{pic6-3} \end {figure} .;- .^ За исключением состояния транзакции UNLOCKED, каждое из них имеет соответствующую блокировку. Таким образом, можно говорить, что соединение имеет 'блокировку в состоянии RESERVED', или соединение находится 'в состоянии RESERVED' или просто 'в RESERVED' - это все значит одно и тоже. За исключением UNLOCKED, чтобы находиться в каком-то состоянии, соединение сначала получает блокировку соответствующую этому состоянию. .^ Транзакция может начинаться или с UNLOCKED, или RESERVED или EXCLUSIVE. По умолчанию, как видно на .;+pic6-3 , транзакция начинается с UNLOCKED. Состояния блокировок из белых прямоугольников - UNLOCKED, PENDING, SHARED или RESERVED - могут существовать в БД при отсутствии соединений с последней. Starting with PENDING in gray, however, things becomes more restrictive. .;--------\ Состояние PENDING в сером прямоугольнике представляет блокировку, которую держит одиночное соединение, назовем его писателем, желающее получить состояние EXCLUSIVE. И напротив, Состояние PENDING в белом прямоугольнике представляет собой способ, которым соединения требуют и освобождают блокировку, чтобы получить состояние SHARED. Не взирая на все представленные состояния блокировок, каждая транзакция в \nm сводится к одному из двух типов: к транзакциям, которые читают; или к транзакциям, которые пишут. В конце концов этот факт отражен на рисунке: как общаются друг с другом читающие и пишущие транзакции. .;3 Read Transactions .3 Читающие Транзакции .^ Сначала просмотрим процесс блокировки оператора $select$. Этот процесс идет очень простым путем. Соединение, которое выполняет оператор $select$, меняется от UNLOCKED к SHARED и, по достижении оператора $commit$, возвращается к UNLOCKED. Конец истории. .^ Теперь, поинтересуемся, что случится при выполнении двух операторов? Какой станет блокировка в этом случае? Ответ зависит от использования или не использования режима автокомита. Рассмотрим следующий пример: .b .;- \includegraphics[width=1.00\textwidth]{./m6_pics/p141_1.png} .;- Сейчес, с явно заданным $begin$, два оператора $select$ выполняются в одиночном соединении и, поэтому, выполняются в одном состоянии SHARED. Первый вызов функции $exec()$ заканчивается, оставляя соединение в SHARED, затем вызывается следущая $exec()$. Наконец, явно выполненный оператор $commit$ переводит соединение из SHARED обратно в UNLOCKED. Все изменения блокировки выглядит следующим образом: .b .;- \includegraphics[width=1.00\textwidth]{./m6_pics/p141_2.png} .;- Теперь рассмотрим случай, как будто бы в примере нет ни оператора $begin$, ни оператора $commit$. Это означает, что два оператора $select$ выполняются в режима автокоммита. Тогда соединение для каждого из них проходит полный цикл изменений своего состояния. Для этого случая блокировка меняется следующим образом: .b .;- \includegraphics[width=1.00\textwidth]{./m6_pics/p141_3.png} .;- Так как в примере просто читаются данные, это не выглядит совсем уж по другому, но в режиме автокоммита таки приходится пройти дважды через блокировку файла. И, как будет вскоре понятно, писатель может встрять между двумя оператора $select$ и изменить БД между вызовами. Таким образом, нельзя быть уверенным, что эти два оператора вернут один и тот же результат. C другой стороны, гарантируется, что при использовании $begin .. commit$ отношения результаты будут идентичными. .3 Write Transactions .3 Пишущие Транзакции .^ Теперь рассмотрим оператор, который пишут в БД, такой как $update$. Во первых, соединение должно менять свое состояние так же как и в случае $select$ и закончится на состоянии SHARED. Любая операция - все равно, читающая или пишущая - должна начинаться с последовательного изменения UNLOCKED $\rightarrow$ PENDING $\rightarrow$ SHARED, причем PENDING, как будет вскоре видно, является основной блокировкой. .;4 The Reserved State .4 Состояние RESERVED .^ В момент, когда соединение пытается записать что нибудь в БД, оно свое состояние SHARED меняет на RESERVED. И начать менять содержимое БД соединение сможет, если блокировка RESERVED таки получена. Даже если и не удастся на деле изменить содержимое БД в этот момент, эти изменения сохранит .x ?pager менеджер страниц в упомянутом ранее .x ?pgch кэше страниц. Именно у этого кэша менялся размер в разделе .;+m4-conf . .^ После перехода соединения в состояние RESERVED, менеджер страниц инициализирует журнал откатов (rollback journal). .x журнал откатов .x rollback journal Как показано на рис. .;+pic6-1 , это файл, который используется для откатов и восстановлений после краха. В частности, он хранит необходимые для восстановления страницы БД в состоянии, которое они имели перед началом транзакцией. В этот файл страницы, изменяемые B-деревом, складирует менеджер страниц. В данном случае, для каждой записи, измененной оператором $update$, менеджер страниц выбирает из БД страницу, содержащую исходную запись и сохраняет её в журнале. То есть, журнал хранит частичное содержание БД до транзакции. Следовательно, все что менеджер страниц должен сделать для отката любой транзакции, это просто скопировать содержимое журнала обратно в файл БД. Тогда БД восстановит свое состояние перед транзакцией. .^ Для состояние RESERVED существует три набора страниц, которыми управляет менеджер страниц; измененные, не измененные и сохраненые в журнале. Измененные страницы - это страницы, которые содержат записи, которые отредактировало B-дерево. Они хранятся в кэше страниц. Не измененные страницы - это страницы, которые B-дерево прочитало, но не меняло. Это результат работы операторов $select$. Наконец. страницы, сохраненные в журнале - это исходные версии отредактированных страниц. Они сохраняются не в кэше страниц, а записаны в журнал перед,собственно, их изменением. .^ Кэш страниц позволяет пишущему соединению закончить свою работу, находясь в состоянии RESERVED без конфликтов с другими читающими соединениями. То есть, \nm эффективно справляется с одновременно работающими, несколькими читающими соединениями и одним пищущим. Хитростью есть то, что пишущее соединение хранит свои изменения в кэше страниц, а не в БД. Запомним, что в один момент времени для данной БД только одно соединение может быть в состоянии RESERVED или EXCLUSIVE - то есть, несколько читающих соеднинений и только одно пишущее. .;4 The Pending State .4 Состояние PENDING .^ Когда соединение завершает все изменения оператора $update$ и приближается время фиксации транзакции, менеджер страниц пытается перейти к состоянии блокировки EXCLUSIVE. Ради полноты картины повторим изложенное в разделе .;+blockDB Манеджер страниц пытается получить блокировку состояния PENDING из состояния RESERVED. Если ему это удается, он находится в нем, предотвращая все другие соединения от перехода в это состояние. Взгянув на .;pic6-3 можно увидеть произведенный эффект. Напомним, что важность блокировки PENDING уже отмечалась. Теперь понятно почему. Так как пишущее соединение находится в состоянии PENDING, ни одно из других соединений не может больше перейти в состояние SHARED из состояния UNLOCKED. Это означает, что теперь не появится ни одного нового соединения с БД; ни читающего, ни пишущего. Это состояния явлется отсеивающим действием. Оно гарантирует, что не зависимо от времени ожидания, пишущее соединение дождется своего. Продолжать свою работу как обычно смогут только те соединения, которые находятся в состоянии SHARED. А пишущее соединение, находясь в PENDING, ожидает их окончания и освобождения их блокировок. Вскоре, в секции .;+m1-5-5 будет указано на дополнительные вопросы происходящие во время ожидания блокировок. ,^ После освобождения всеми соединениями их блокировок, БД переходит в монопольное владение к пишущему соединению. Значит менеджер страниц может поменять состояние блокировки своего соединения из PENDING в EXCLUSIVE. .;---- 666666 ... |
|||
:
Нравится:
Не нравится:
|
|||
26.07.2018, 16:47 |
|
книжки по Sqlite на русском языке..
|
|||
---|---|---|---|
#18+
писатель может встрять остановиться между двумя операторами $select$ и изменить БД между вызовами в это время произойдет изменение БД в другом соединении И соединение сможет начать менять содержимое БД соединение сможет, если блокировка RESERVED таки получена. Для состояниея RESERVED Это состоянияе является отсеивающим действием. ... |
|||
:
Нравится:
Не нравится:
|
|||
27.07.2018, 08:27 |
|
книжки по Sqlite на русском языке..
|
|||
---|---|---|---|
#18+
авторписатель может остановиться между двумя операторами $select$ -- та ну. писатель может успеть сработать между двумя операторами $select$ ... |
|||
:
Нравится:
Не нравится:
|
|||
27.07.2018, 10:16 |
|
книжки по Sqlite на русском языке..
|
|||
---|---|---|---|
#18+
tchingizавторписатель может остановиться между двумя операторами $select$ -- та ну. писатель может успеть сработать между двумя операторами $select$ Да, не заметил что речь о внешнем писателе. Думаю как-то так надо "Другой писатель может успеть ..." ... |
|||
:
Нравится:
Не нравится:
|
|||
27.07.2018, 10:45 |
|
книжки по Sqlite на русском языке..
|
|||
---|---|---|---|
#18+
меня этот писатель вообще раздражает авторИ, как вскоре будет понятно, другое соединение может успеть сработать между двумя операторами $select$ и изменить БД. ... |
|||
:
Нравится:
Не нравится:
|
|||
27.07.2018, 12:36 |
|
книжки по Sqlite на русском языке..
|
|||
---|---|---|---|
#18+
.;---- 666666 .;4 The Exclusive State .4 Состояние EXCLUSIVE .^ В состоянии EXCLUSIVE, главное задание заключается в переносе изменённых страниц из кэша страниц в файл БД. .;Все становится более ответственным, так как менеджер страниц .;собирается в действительности изменять БД. Пеоед началом записи этих страниц, он обращается к журналу. Он убеждается, что все содержимое журнала уже записано на диск. В этот момент очень вероятно, что хотя менеджер страниц уже записал нужное в файл журнала, операционная система буферизовала многие, если не все из них в оперативной памяти. В этот момент начинает использоваться, описанная в разделе .;+m4-conf прагма синхронизации - $synhronous$. Метод, заданный прагмой, определяет насколько тщательно менеджер страниц обеспечивает вывод операционной системой страниц журнала на диск. Нормальное установка заключается в выполнении полной синхронизации перед продолжением работы, операционная система должна подтвердить реальную запись всех буферизованных страниц журнала на поверхность диска. Если прагма $synhronous$ установлена в $FULL$, менеджер страниц выполняет две полных синхронизации перед продолжением. Если прагма $synhronous$ установлена в $NONE$, менеджер страниц не заботится о журнале вообще (и раз он может быть в 50 раз быстрее, можно забыть о надеждности транзакций). .^ Журнал это единственная возможность восстановить файл БД после краха приложения или операционной системы в момент записи в БД менеджером страниц, поэтому фиксация журнала на диске так важна. Невозможно вернуть БД в начальное состояние, так как страницы, не перенесенные из оперативной памяти на диск перед крахом системы оказываются потерянными навсегда. В лучшем случае, БД окажется в несогласованном состоянии, в худшем - файл окажется испорченным. .! Внимание Даже если было использовано наиболее консервативное значение для прагмы $synhronous$ журнал может все таки не полностью сбросится на диск. Это не вина \nm, это следствие определенных типов аппаратных средств или операционных систем. \nm использует системный вызов $fsync()$ под Юниксами и $FlushFileBuffers()$ под Windows чтобы заставить записать страницы журнала на диск. Однако есть сообщения о том, что эти функции не всегда работают, особенно на дешеввых IDE дисках. По всей видимости, некоторые производители IDE дисков используют микросхемы, которые привирают о реальном состоянии дел при записи. В некоторых случаях микросхемы кешируют данные и сообщают что они уже записаны на поверхность диска. Кроме этого, есть сообщения (непровереные) о том, что Windows иногда игнорирует вызовы $FlushFileBuffers()$. Таким образом, в случае сомнительных программных или аппаратных средств надежность транзакций может пострадать. .! .^ Как только менеджер страниц позаботился о журнале, он копирует все измененные страницы в файл БД. Что произойдет потом, записит от режима транзации. В случае автофиксации транзакций менеджер страниц очищает журнал и кэш страниц, переходит из состояния EXCLUSIVE в UNLOCKED. Если транзакция не добралась до фиксации, то менеджер страниц продолжает держать состояние блокировки EXCLUSIVE и журнал используется до достижения либо оператора $commit$, либо оператора $rollback$. .;4 Autocommit and Efficiency .4 Автофиксация и Производительность .^ С полученным багажем знаний, рассмотрим чем отличается оператор $update$, выполняемый в явной транзакции, от оператора $update$, выполняемого в режиме автофиксации. При автофиксации каждая команда, изменяющая БД в отдельной транзацкии последовательно меняет свои состояния следующим образом: .b .;- \includegraphics[width=1.00\textwidth]{./m6_pics/p143_1.png} .;- .^ При этом, каждый такой цикл включает в себя создание, фиксацию и очистку журнала откатов. Несмотря на то, что выполнение нескольких выборок в режиме автофиксации не является проблемой с точки зрения эффективности, необходимо тщательно обдумать использование автофиксации для частых запросов на запись. Ведь, как упоминалось в случае $select$, при выполнении несколькоих операторов с автофиксацией, ничто не сможет удержать другое работающее соединение от изменения БД между операторами. По этой причине, еесли два обновления БД зависят от заданных значений в данных, требуется всегда выполнять их в одной и той же транзакции. .= Блокировки и восстановление .^ В \nm реализация блокировок использует обычный файл блокировки. \nm есть три различных файла блокировок для файла БД: резервированный байт (reserved byte), байт ожидания (pending byte) и разделяемая область (shared region). .x резервированный байт .x reserved byte .x байт ожидания .x pending byte .x разделяемая область .x shared region .b .;- \includegraphics[width=1.00\textwidth]{./m6_pics/p144_1.png} .;- Все начинается с байта ожидания. Чтобы перейти от состояния UNLOCKED к SHARED соединение пробует взять блокировку для чтения на байте ожидания. .;------- хрень какаято to get a read-lock on the pending byte. В случае успеха, соединение берет блокировку для чтения на случайном байте в разделяемой области и возвращает блокировку для чтения на байте ожидания. Чтобы изменить состояние от SHARED к RESERVED, соединение вытается получить блокировку записи для байта ожидания. В случае успеха, это приводит к процессу истощения, так как не позволяет другим соединениям брать блокировку для чтения на байте ожидания, чтобы перейти к состоянию SHARED. Наконец, чтобы изменить состояние своей блокировки на EXCLUSIVE, соединение пробует получить блокировку для чтения на всей разделяемой области. Так как разделяемая область содержит блокировки для чтения всех остальных активных соединений, этот шаг гарантирует, что блокировка соединения перейдет в состояние EXCLUSIVE только после того, как сначала все другие блокировки соединений освободят состояние SHARED. .b Механизм восстановления после краха в \nm использует резервированный байт чтобы определить требуется ли восстановление БД, Так как файл журнала и блокировка RESERVED передается из рук в руки, менеджер страниц видит журнал без блокировки, .; if the pager sees the former without the latter, ------ если случилось что то плохое. Такая проверка целостности выполняется каждый раз, когда менеджер страниц открывает БД или пытается получить страницу из неё. Наличие файла журнала и отсутствие блокировки RESERVED на БД означает, что процесс, создавший журнал потерпел крах или упала операционая система. В этом случае журнал называет горячим журналом и считается что БД может находится в противоречивом состоянии. Такой журнал должен быть 'отыгран назад', чтобы восстановить то состояния БД, которое было перед прерыванием транзакции. .b Для этого менеджер страниц переводит БД в режим восстановления. Для этого, как показано выше (и на рис. .;+pic6-3 ) менеджер изменяет свое состояние от SHARED прямо к PENDING. Такой переход возможен только в єтой ситуации. Есть две причины, чтобы пропустить состояние RESERVED. Во-первых, блокирование байта ожидания не допускает никаких новых соединений с БД. Во-вторых, уже существующие соединения с БД (в состоянии SHARED) при следующей попытке доступиться к странице увидят, что журнал горячий. Такие соединения тоже попробуют перейти в режим восстановления и отыграть журнал. Однако не смогут сделать это, так как первое соединение уже захватило блокировку PENDING. То есть, немедленно меняя блокировку SHARED на PENDING, первое соединение может быть уверенно, что новых соединений с БД не появится, соединения с БД уже находящиеся в состоянии SHARED не смогут начать восстановление БД. Работа всех, кроме начавшего восстановление соединения, приостановлена. .b В основном, горячий журнал являетя неявной блокировкой EXCLUSIVE. После краха пишущего соединения в БД невозможна никакая активность до тех пор, пока одно из соединений не восстановит её. При попытке доступа к любой странице следующий менеджер страниц увидит горячий журнал, блокирующий все и начнет восстановление. При отсутствии активных соединений, горячий журнал обнаружит первое приложение, попытавшееся соединяться с БД. Оно же и начнет восстановление. .= .;2 +m1-5-4 Tuning the Page Cache .2 +m1-5-4 Настройка Кэша Страниц .^ Предположим, предыдущий пример был изменен, теперь он начинается с оператора $begin$, за которым следуют $update$. Причем в процессе всех изменений переполняется кэш страниц. Как на это отреагирует \nm? То есть, $update$ потребует хранить больше страниц, чем может поместиться в кэше страниц. Что теперь произойдет? .;3 Переход в Состояние EXCLUSIVE .3 Transitioning to Exclusive .^ Что конкретно делает менеджер страниц, меняя состояние RESERVED на EXCLUSIVE и почему? Существует два сценария и будут рассмотрены оба из них. Либо соединение достигает момента фиксации изменений и явно начинает блокировку EXCLUSIVE, либо кэш страниц переполняется без возможности какого либо выбора. Рассмотрим первый сценарий. Что случается при заполнении кэша страниц? Выражаясь простым языком, менеджер больше не может запомнить ни одной измененной страницы и, естественно, не может выполнять свою работу. Его переводят в состояние EXCLUSIVE, чтобы продолжать. На деле, это не совсем правда, потому что существуют мягкий и жесткий пределы. .^ .;------- Первому заполнению кэша страниц соответствует мягкий предел. В этот момент кэш хранит смесь из неизмененных и измененных страниц. Менеджер страниц пытается очистить кэш. Он проходит по кэшу избавляясь от неизмененных страниц. После очистки менеджер продолжать работу с памятью до тех пор, пока кэш не заполнится снова. Далее, если есть хоть одна неизмененная страница, можно повторить процесс очистки от них. Это означает появление жесткого предела. В этот момент менеджер страниц не имеет другой возможности, кроме как переходить к состоянию EXCLUSIVE. .^ С ругой стороны, прагма $cach\_size$, проявляется в состоянии RESERVED. Как объяснялось в секции .;+m4-conf , прагма управляет размером кэша страниц. Чем больше кэш, тем больше измененных страниц в нем может запомнить менеджер страниц и тем больше работы соединение может выполнить, не меняя свое состояние на EXCLUSIVE. И, как отмечалось выше, выполнение работы в состоянии RESERVED уменьшает время, когда соединение находится в состоянии EXCLUSIVE. Если все закончено в RESERVED, то EXCLUSIVE нуже исключительно на время сбрасывания измененных страниц на диск, не для компиляции следующих запросов, и обработки результатов и, затем, вывода на диск. .; overall concurrency ------??. Обработка, которыя выполняется в состоянии RESERVED, может значинельно улучшить общую производительность. При больших транзакциях, перегруженной БД и доступной памяти было бы идеально, чтобы размер кэша позволял находиться соединению в RESERVED так долго как возможно. .3 Выбор Размера Кэша .;3 Sizing the Page Cache .^ Итак, как подобрать размер кэша? Это зависит от выполняемой работы. Поедположим, требуется поменять каждую запись в таблице $episodes$. В этом случае каждая страница таблицы будет изменена. То есть, надо узнать размер таблицы $episodes$ в страницах и соответственно изменить размер кэша страниц. Для получения такой информации о таблице $episodes$ требуется использовать sqlite3\_analyzer.exe. Для каждой таблицы он может вывалить детальную статистику, включая считчик страниц. К примеру, для таблицы $episodes$ из БД $foods$ можно получить следующую информацию: .b .;- \includegraphics[width=1.00\textwidth]{./m6_pics/p146_1.png} .;- .b .;- \includegraphics[width=1.00\textwidth]{./m6_pics/p146_2.png} .;- Общее число страниц таблицы - 5. Четыре страницы действительно отведено под таблицу, и одна - под индекс. Поскольку умолчательный размер кэша - 2000 страниц, то волноваться не о чем. В таблице 400 записей, следовательно, каждая страница хранит 100 записей. Не зачем беспокоится об изменении кэша, до тех пор, пока не придется менять каждую из, по меньшей мере, 196 000 записей в таблице $episodes$. И, вообще, этим нужно заниматься при нескольких соединениях с БД и решении вопроса конкуренции. Для одиночного пользователя БД это все не имеет значения. .;2 +m1-5-5 Waiting for Locks .2 +m1-5-5 Ожидание Блокировок .^ Ранее упоминался менеджер страниц, ожидающий смену состояния с PENDING на EXCLUSIVE. Но что конкретно подразумевает это ожидание блокировки? .;-----What exactly is involved with waiting on a lock? Во-первых, ожидание блокировки может повлечь любой вызов $exec()$ или $step()$. Всякий раз, когда \nm натыкается на ситуацию, когда он не может получить блокировку, умолчательным поведением является возврат признак SQLITE\_BUSY в фукнцию, которая её просит. Признак SQLITE\_BUSY можно получить не зависимо от исполняемого оператора. Как уже известно, даже оператор $select$ может сбойнуть на попытке получить блокировку SHARED, если пишущее соединение пишет или находится в состоянии PENDING. Самое простое, что можно сделать поосле получения SQLITE\_BUSY - это повторить предыдущий вызов. Однако, вскоре будет ясно, что это не всегда лучший способ поведения. .;3 Using a Busy Handler .3 Испльзование Обработчика Занятости .^ Вместо циклического вызова функций снова и снова, можно использовать обработчик занятости (busy handler). .x обработчик занятости .x busy handler Вместо упорного вызывания функций, возвращающие SQLITE\_BUSY, когда соединение не может получить блокировку, лучше начать использовать обработчик занятости. .^ Обработчик занятости - это функция, которую пишут, чтобы убить время. Она может делать что либо ещё, вроде заботливой рассылки спама тещам. Обработчики занятости предполагается вызывать, когда \nm не может получить блокировку. Единственное, что обязан сделать обработчик это предоставить код возврата, уведомляющий \nm о требуемых следующих действиях. Если обработчик возвращает true, то \nm будет продолжать попытки получить блокировку. .;---------- Если обработчик возвращает false, то \nm вернет SQLITE\_BUSY в функцию. запрашивающую блокировку. Рассмотрим следующий пример: .;----------7777 ... |
|||
:
Нравится:
Не нравится:
|
|||
28.07.2018, 10:46 |
|
книжки по Sqlite на русском языке..
|
|||
---|---|---|---|
#18+
В состоянии EXCLUSIVE, главное задание заключается в переносе происходит сохранение изменённых страниц из кэша страниц в файл БД. Пеоред началом записи этих страниц В этот момент очень вероятно возможно, что хотя менеджер страниц уже записал нужное нужные страницы в файл журнала, но операционная система ... (и раз при этом он может быть в 50 раз быстрее, но можно забыть о надеждности транзакций). на дешеввых IDE дисках Что произойдет потом, запвисит от режима транзакции. соединение пробует взять установить блокировку для чтения на байте ожидания. ИМХО тут автор попытался кратко описать устройство механизма блокировок, но у него это не получилось, а получились непонятные обрывки подробностей. С другой стороны, прагма $cach\_size$, Обработка, которыая выполняется в состоянии RESERVED, возврат признак SQLITE\_BUSY в функнцию Самое простое, что можно сделать поосле .3 Использование Обработчика Занятости ... |
|||
:
Нравится:
Не нравится:
|
|||
28.07.2018, 17:11 |
|
книжки по Sqlite на русском языке..
|
|||
---|---|---|---|
#18+
Dima Tсоединение пробует взять установить блокировку для чтения на байте ожидания. ИМХО тут автор попытался кратко описать устройство механизма блокировок, но у него это не получилось, а получились непонятные обрывки подробностей. угу, я лелеял надежду, что ты понял что там написано, пока продирался через эту ахинею. надо еще долго перечитывать автор.;----------7777 .b .;- \includegraphics[width=1.00\textwidth]{./m6_pics/p147_1.png} .;- .b .;- \includegraphics[width=1.00\textwidth]{./m6_pics/p147_2.png} .;- Собственно, разработка функции $spam\_mother\_in\_law()$ остается как упражнение для читателя. .^ Функция $step()$ должна получить блокировку SHARED в БД, чтобы выполнить оператор $select$. Предположим, с этой БД есть еще активное пишущее соединение. Тогда обычно функция $step()$ возвращает SQLITE\_BUSY. Однако в нашем случае это не так. Здесть менеджер страниц (тот из них, который обращается за блокировкой) вместо этого вызывает функцию $busy()$, так как она была зарегистрирована в качестве обработчика занятости. $busy()$ увеличивает счетчик $counter$, посылает теще сотню случайных писем из своей папки со спамом и возвращает 1. Менеджер страниц интерпретирует её как true (сигнал продолжать захватывать блокировку) и повторяет попытку получить блокировку SHARED. На этот раз, $busy()$ возвращает 0, который воспринимается как false. Тогда менеджер страниц, вместо повторения захвата блокировки, возвращает код SQLITE\_BUSY, которым закончится работа функции $step()$. .^ Разрабатывать обработчик занятовсти просто для ожидания (чтобы убить время) нет нужды. Он уже есть в программный интерфейс \nm. Это функция, которая просто засыпает на заданный период времени для ожидания блокировки. Её название $sqlite3\_busy\_timeout()$ и поддерживается библиотеками некоторых языков расширений. По существу можно просто сказать 'засни на 10 секунд, если не сможешь получить блокировку' и менеджер страниц сделает это. Он подождет 10 секунд, и затем, если не сможет получить блокировку, вернет SQLITE\_BUSY. .;3 Using the Right Transaction .3 Правильное Использование Транзакций .^ Ещё раз пересмотрим предыдущий пример, но теперь в нем заменим оператор $select$, на оператор $update$. Что на деле будет означать SQLITE\_BUSY? После применения $select$ это просто значит: 'Я не могу получить блокировку SHARED'. А что это значит в случае $update$? На деле, это неизвестно. SQLITE\_BUSY может означать, что соединение не смогло получить блокировку SHARED, в связи с наличием другого пишущего соединения в состоянии PENDING. Это может означать, что соединение, получив SHARED, не может получить RESERVED. Отличие в том, что не известно состояние БД или состояние рассматриваемого соединения. SQLITE\_BUSY для запросов на запись полностью неопределен в режиме автофиксации. Итак, что же теперь делать дальше? Надо ли вызывать $step()$ снова и снова, пока оператор не выполнится? .^ над этим надо подумать. Предположим, попытка получить блокировку SHARED, а не RESERVED, закончилась SQLITE\_BUSY и теперь соединение удерживает состояние RESERVED. .:++++ Suppose SQLITE_BUSY was the result of you getting a SHARED lock but not RESERVED, .:++++ and now you are holding up a connection in RESERVED from getting to EXCLUSIVE. Напомним, состояние БД - не известно. И нахрапистая попытка любой ценой выполнять свою транзакцию не обязательно завершится удачей, и в рассматриваемом соединении, и в любом другом. Попытки вызова $step()$ заведут в тупик -- в задницу соединения в состоянии RESERVED, и, если никто из двоих не сбойнет, к клинчу. .= Замечание \nm пытается избежать клинча в конкретно этом сценарии, игнорируя вызов обработчика занятости (busy handler), .x обработчик занятости .x busy handler .;++++ Обработчик занятости соединения в состоянии SHARED не вызывается, если предполагается, что он будет мешать завершиться соединению в состоянии RESERVED. .;++++ However, it is up to the code to get the hint. Приложение может просто продолжать вызывать $step()$, и, в этом случае, ничто не спасет \nm .= Поэтому запрос на запись надо начинать с $begin immediate$. По крайней мере, при получении ответа SQLITE\_BUSY, будет известно состояние соединения. Пишущее соединение сможет повторять свои попытки без блокирования другого соединения. И известно, что при достижении успеха, пишущее соединение переходит в состояние RESERVED. .;Now you can use brute force if you have to because you are the one in the right. Теперь можно делать что угодно. С другой стороны, $begin immediate$ является гарантией что не придется иметь дела с условиями занятости вообще. Но при этом надо помнить, что пишущее соединение находится в состоянии EXCLUSIVE, которое снижает эффективность многократных соединений, по сравнению с работой в состоянием RESERVED. .= .4 Блокировки и Сетевая Файловая Система .^ Теперь можно иметь хорошее представление о трудностях использования файла ДБ через сетевую файловую систему (в расшаренном каталоге). \nm поддерживает многократные соединения размещая файл блокировки в файловой системе. Очень важно, чтобы этот файл и размещался и удалялся в правильные моменты времени. Корректность управления блокировками многократных соединения у \nm полностью зависит от файловой системы. Под Unix \nm использует POSIX advisory locks, а под Windows - OS X и системные вызовы $LockFile()$ $LockFileEx()$$UnlockFile()$. Эти стандартные системные вызовы корректно работают в несетевой файловой системе. Сетевая файловая система эмулирует работу обычной. И, к сожалению, в некоторых реализациях эта эмуляция не всегда корректна. Даже в случае корректной работы сетевой файловой системы остаются поводы для размышлений. .^ Возьмем к примеру NFS. Это отличная сетевая файловая система. Однако, исходная реализация NFS имеет известные ошибки и, в некоторых случаях, не имеет реализованніх блокировок. Это означает серьезную проблему для \nm. Без блокировок два соединения могут перейти в состояние EXCLUSIVE на одной ДБ и в одно время, что приведет к определенным нарушениям целостности. Это не проблема NFS вообще, это проблема некоторых её реализаций. Благодаря последним реализациям NFS эти трудности преодолены и некоторые из них (такие, которые используются в Sun) вполне работоспособны. .; в виндюках это не надо .;2 +m1-5-6 Code .2 +m1-5-6 Прикладные Программы .^ Наконец, получена хорошая картина для программного интерфейса, транзакций и блокировок. Чтобы покончить с этим, рассмотрим все это с точки зрения прикладной программы и рассмотрим пару сценариев, которые было бы желательно обсудить. .;3 Using Multiple Connections .3 Использование Нескольких Соединений .^ Опытные программисты могут написать приложение, использующее несколько соединений. Классический пример: одно соединение проходит по таблице в то время, как другое изменяет её. Такие приожения могут приводить к трудностям в работе \nm, поэтому их надо аккуратно обдумывать. Рассмотрим пример: .b .;- \includegraphics[width=1.00\textwidth]{./m6_pics/p149_1.png} .;- .b .;- \includegraphics[width=1.00\textwidth]{./m6_pics/p149_2.png} .;- .; we bet Можно спорить, что здесь легко указать трудность. Находясь в цикле $while$, соединение $c2$ выполняет обновления таблицы, в то время как соединение $c1$ имеет блокировку в состоянии SHARED. Эта блокировка не будет освобождена до финализации оператора $stmt$ после цикла. Таким образом, нет никакой возможности выполнить запрос обновления БД внутри цикла. Либо $c2.exec()$ будет тихо сбоить, либо, в случае обработчиков занятости, они будут просто тормозить приложение. Более правильная версия этого примера должна использовать одно соединения и выполнять запросы в рамках транзакции $begin immediate$. Новую версию приводим ниже: .b .;- \includegraphics[width=1.00\textwidth]{./m6_pics/p149_3.png} .;- .b .;- \includegraphics[width=1.00\textwidth]{./m6_pics/p150_1.png} .;- .^ В подобных случаях надо использовать операторы из одного соединения для запросов чтения и записи. Тогда не зачем беспокоиться о трудностях, вызываемых блокировками БД. Но, как оказывается, этот конкретный пример остается нерабочим. .;----- ???? Процесс блокирование при чтение таблицы одним оператором и редактирование её другим имеет дополнительную тонкость, которую тоже надо знать. Сейчас она будет раскрыта. .;3 The Importance of Finalizing .3 Важность Финализации .^ Обычной промашкой в обработке оператора $select$ является непонимание того, что блокировка SHARED не обязательно освобождается при вызове фунгкции $finalize()$ ( или $reset()$), более того, обычно не освобождается. .; +++++ переспросить Рассмотрим пример: .b .;- \includegraphics[width=1.00\textwidth]{./m6_pics/p150_2.png} .;- Хотя так программы на практике не пишут, это можно написать случайно, просто потому, что так можно сделать. .;++++ you might end up doing it anyway by accident simply because you can get away with it. Эквивалент этого примера, написанный с помощью программного интерфейса C, будет на деле работать. Даже если не вызвать $finalize()$, второе соединение изменит БД безо всяких проблем. Прежде чем сказать почему, взглянем на следующий пример: .b .;- \includegraphics[width=1.00\textwidth]{./m6_pics/p150_3.png} .;- Предположем в таблице $episodes$ есть 100 запией. Приложение прошло только три из них. Что случиться теперь? Вторе приложение получит SQLITE\_BUSY. .^ В предыдущем примере, \nm освобождает блокировку SHARED, когда оператор достигает окончания отношение результата. То есть, в момент последнего вызова $step()$, на котором программный интерфейс C возвращает SQLITE\_DONE, VDBE встреить инструкцию $Close$ и \nm закроет курсор и сбросит блокировку SHARED. То есть, $c2$ будет иметь возможность выполнить свой $insert$ .; не было инсерта был апдайет ------ хотя $c1$ еще не вызвал $finalize()$. .^ Во втором случае, оператор $select$ не достиг последней записи из отношения результата. Поэтому следующий выхов $step()$ должен вернуть SQLITE\_RESULT, что означает наличие непрочитанных записей в отношении результате, это же означает, что блокировка SHARED остается. Значит, $c2$ не может из - за неё выполнить $insert$. .; на деле $update$ .^ Мораль этой истории в том, что не надо делать все, что можно. Вызовать $finalize()$ или $reset()$ перед запросами на редактирование нужно всегда, когда есть другие соединения. Также хорошо бы помнить, что $step()$ и $finalize()$ в режиме автофиксации более или менее ограничивают транщакции и блокировки. Они начинают и заканивают транзакции. Они начинают и освобождают блокировки. .; ++++++ .; The other thing to remember is that in autocommit mode step() and finalize() .; are more or less transaction and lock boundaries Нужно очень аккуратно работать в другом соединении между этими двумя функциями. .3 Режим Разделяемого Кэша .;3 Shared Cache Mode .^ Теперь, когда все понятно про правила работы конкурирующих соединений, настало время для некоторого усложенния. \nm имеет еще одну модель для конкурирующих соединений, которая называется режим разделяемого кэша. Она относится (регулирует / позволяет??) к работе соединений внутри отдельных нитей. .;++++ .^ В этом режиме нити могут создавать несколько соединений, которые сообща используют (разделяют) один и тот же самый кэш страниц. .x разделяют .x сообща используют Более того, такая группа соединения может иметь несколько читающих соединений и одно пишущее (в состоянии EXCLUSIVE), работающих в одно время с одной и той же БД. Уловкой есть то, что эти соединения из разных нитей не могут разделять кэш, они строго ограничены одной нитью (именно работающей в режиме разделяемого кэша), создавшей их. Более того, пишущие и читающие соединения должны быть готовы обрабатывать специальные условия включающие блокировку таблиц. .^ Когда читающие соединения читают таблицы, \nm автоматически создает блокировку таблиц для них. Это предохраняет таблицы от изменения пишущим соединением. Если пишущее соединение пытается изменить таблицу, заблокированную для чтения, то получает SQLITE\_LOCKED. Та же логика применяется к читающим соединениям, пытающимся обратиться к таблицам заблокированным для записи. Однако в этом случае, читающие соединнения могут идти далее и читать таблицы, которые были изменены пишущим соединением. Правда оно должно работать в специальном режиме (read-uncommitted mode) чтения не фиксированных данных. .x read-uncommitted mode .x режиме чтения не зафиксированных данных Его можно задавать при помощи прагмы $read\_uncommitted$ .x read\_uncommitted .x прагма read\_uncommitted В этом случае \nm не ставит на таблицы блокировку чтения. Как результат, читающие соединения вообще не замечают пишущее. Однако, тогда они могут получить несогласованные данные, так ак пишущее соединение может изменить таблицы во время чтения. Этот режим похож на уровень изолирования транзацкий с названием грязное чтение. .x грязное чтение .^ Этот режим разработан для встраиваемых серверов, которые нуждаются в экономии оперативной памяти и в легком усилении конкуренции в определенных ситауциях. Дополнительную информацию о том, как использовать этот режим с программным интерфейсом для C можно найти в гл. .;+m1-6 . .;2 +m1-5-7 Summary .2 +m1-5-7 Итого .^ Программный интерфейс \nm гибкий, интуитивно понятный и легкий в использовании. Он состоит из двух основных частей: базовый интерфейс и дополнительный. Базовый интерфейс вращается возле двух основных структур данных, которые используются для выполнения команд SQL: соединений (connection) и операторов (statement). Операторы выполняются за три шага: компиляция, выполнение и финализация. Функции SQL $exec()$ и $get\_table()$ выполняют эти три шага за один вызов функции, автоматически обрабатывая объекты, ассоциированные с операторами. Дополнительный интерфейс предоставляет возможности для дополнительной настройки \nm треми способами: при помощи функций, определяемых пользователем; при помощи групповых функций, определяемых пользователем; при помощи сортирующих последовательностей, определяемых пользователем. .^ Так как модель конкуренции в \nm несколько отличается от других СУБД, то важно иметь некоторое понимание как \nm управляется с транзакциями и блокировками, как они на деле выполняются и как они работают внутри кода пользователя. Вообще говоря, эти концепции не трудны для понимания и состоят из нескольких простых правил, которые необходимо помнить, чтобы разрабатывать программы с использованием \nm . .^ Все, уже рассказанное выше, будет уточняться в последующих главах, так как эти концепции применимы не только к программному интерфейсу для языка C, но к другим языкам, поскольку они построены на использовании интерфейса для C. ... |
|||
:
Нравится:
Не нравится:
|
|||
28.07.2018, 17:58 |
|
книжки по Sqlite на русском языке..
|
|||
---|---|---|---|
#18+
упс ... |
|||
:
Нравится:
Не нравится:
|
|||
28.07.2018, 17:59 |
|
книжки по Sqlite на русском языке..
|
|||
---|---|---|---|
#18+
Dima T В этот момент очень вероятно возможно, что хотя менеджер страниц уже записал нужное нужные страницы в файл журнала, но операционная система ... я это все стер и переписал по своему. авторТак как менеджер страниц собираюет изменять БД, то лежащая на нем ответственность возрастает. И работу эту надо сделать с максимальной тщательностью. Перед началом вывода этих страниц в БД, он обращается к журналу. От него требуется убедиться, что все содержимое журнала уже записано на диск (в его файле). Вероятно, что операционная система продолжает хранить многое, если не все в оперативной памяти, несмотря на уже выполненные системные вызовы От менеджера требуется еще раз (выполнив другие системные вызовы) потребовать от неё завершить вывод этих страниц на поверхность диска в буквальном смысле. ... |
|||
:
Нравится:
Не нравится:
|
|||
28.07.2018, 18:20 |
|
книжки по Sqlite на русском языке..
|
|||
---|---|---|---|
#18+
автор.= Замечание \nm пытается избежать клинча в конкретно этом сценарии, игнорируя вызов обработчика занятости (busy handler), .x обработчик занятости .x busy handler .;++++ Обработчик занятости соединения в состоянии SHARED не вызывается, если предполагается, что он будет мешать завершиться соединению в состоянии RESERVED. .;++++ However, it is up to the code to get the hint. Приложение может просто продолжать вызывать $step()$, и, в этом случае, ничто не спасет \nm .= заменил на автор.= Замечание \nm пытается избежать клинча в конкретно этом сценарии, игнорируя вызов обработчика занятости (busy handler), .x обработчик занятости .x busy handler .;++++ Обработчик занятости соединения в состоянии SHARED не вызывается, если предполагается, что он будет мешать завершиться соединению в состоянии RESERVED. Однако, понята ли подсказка зависит полсностью от приложения. .;++++ However, it is up to the code to get the hint. В случае, если оно будет просто продолжать вызывы $step()$ ничто не спасет \nm. .= ... |
|||
:
Нравится:
Не нравится:
|
|||
28.07.2018, 18:37 |
|
книжки по Sqlite на русском языке..
|
|||
---|---|---|---|
#18+
... |
|||
:
Нравится:
Не нравится:
|
|||
28.07.2018, 19:11 |
|
книжки по Sqlite на русском языке..
|
|||
---|---|---|---|
#18+
По чистовику c.112 что бы (слитно пишется) понять c.112 начинается со введения c.112 основным подсистемами SQLite с.113 базовый программный интрефейс и расшеиренный. с.113 что бы (слитно пишется) разрабатывать с.114 Рис. 6.1 отсутствует с.115 The B-дерево и Менеджер Страниц с.115 менеджер страниц что бы (слитно пишется) читать с.115 Существует два важных метода для выполнения команд SQL: подготовленные запросы и wrapped запросы. Подготовленные запросы является Prepared queries are the way in which SQLite ultimately executes all commands, both in the API and internally. (надо бы все по-русски) с.115 трех фазный (слитно пишется) процесс с.116 существует две wrapper функции вроде решили их называть "немедленными" 21593584 с.116 для этого нужно использовать либо строчку ry :memory: с.118 На рис. 6.2 изображены эти с.120 значения для подставновки с.120 связать новый набор значений со уже откомпилированным с.120 Замечание переводчика В примере, по видимому, отсутствует вызов функции step() с.120 Executing Wrapped Queries wrapped (надо бы все по-русски) с.122 при использовании wrapped (надо бы все по-русски) с.122 Formatting SQL Statements (надо бы все по-русски) с.123 Атака при помощи SQL инъекции ИМХО слабовато выделено, в оригинале это вставки на сером фоне, а тут смотрится как очередной абзац с.123 Приложение становится уязвимым для атакаи при помощи SQL инъ-екции, если будет полагаеться с.123 Если не внимательно (слитно пишется) относиться с.123 Operational Control (надо бы все по-русски) Усталь, продолжение завтра :) ... |
|||
:
Нравится:
Не нравится:
|
|||
29.07.2018, 20:54 |
|
книжки по Sqlite на русском языке..
|
|||
---|---|---|---|
#18+
с.124 Замечание переводчика В примере, по видимому, с.124 для использования во много-поточныхой среде. с.125 User-defined extensions must be registered on a connection-by-connection basis as they are stored in program memory (надо бы все по-русски) с.127 объяснить в каком состоянии находится с.128 это оазначает, что каждый оператор с.130 Сейчеас, с явно заданным с.130 6.3.4 Write Transactions (Похоже лишняя глава) с.130 Теперь рассмотрим оператор, который пишует в БД, с.131 которое они имели перед началом транзакциейии. с.131 Для состояниея RESERVED существует с.131 Хитростью есть является то, что пишущее соединение с.132 состояниию блокировки EXCLUSIVE. с.132 И теперь окаозывается задействованной с.132 Нормальноеая установка заключается с.135 6.4.1 Transitioning to Exclusive (надо бы все по-русски) с.136 то EXCLUSIVE нужен исключительно с.136 Пор-едположим, требуется с.137 возврат SQLITE_BUSY в функцию, которая её просит. ?? с.138 Разрабатывать обработчик занятовсти с.141 Процесс блокированиея при чтениеи таблицы с.141 Предположеим в таблице с.142 транщзакции и блокировки. Они начинают и заканчивают с.142 Она относится (регулирует / позволяет??) с.142 несогласованные данные, так как пишущее с.143 тремия способа-ми: ... |
|||
:
Нравится:
Не нравится:
|
|||
30.07.2018, 09:52 |
|
книжки по Sqlite на русском языке..
|
|||
---|---|---|---|
#18+
Dima TПо чистовику c.112 что бы (слитно пишется) понять Усталь, продолжение завтра :) грепом нашел 27 вхождений неправильного что бы и заменил ))) ... |
|||
:
Нравится:
Не нравится:
|
|||
31.07.2018, 15:23 |
|
книжки по Sqlite на русском языке..
|
|||
---|---|---|---|
#18+
Dima T, авторс.123 Атака при помощи SQL инъекции ИМХО слабовато выделено, в оригинале это вставки на сером фоне, а тут смотрится как очередной абзац наконец, узнал как менять фон ... |
|||
:
Нравится:
Не нравится:
|
|||
31.07.2018, 18:53 |
|
книжки по Sqlite на русском языке..
|
|||
---|---|---|---|
#18+
большую часть пофискил. авторExecuting Wrapped Queries wrapped (надо бы все по-русски) с этим я пока подожду, чешутся руки переписать эти объяснения. После консультаций с White Owl, мне кажется надо не операторы делить на подготавливаемые и немедленно выполняемые, а функции из апи поделить на две группы : группа, которая подготавливает операторы и группа, которая немедленно выполняет операторы. ... |
|||
:
Нравится:
Не нравится:
|
|||
31.07.2018, 19:58 |
|
книжки по Sqlite на русском языке..
|
|||
---|---|---|---|
#18+
... |
|||
:
Нравится:
Не нравится:
|
|||
31.07.2018, 20:06 |
|
|
start [/forum/topic.php?fid=54&msg=39680504&tid=2008423]: |
0ms |
get settings: |
9ms |
get forum list: |
13ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
35ms |
get topic data: |
10ms |
get forum data: |
3ms |
get page messages: |
60ms |
get tp. blocked users: |
1ms |
others: | 255ms |
total: | 392ms |
0 / 0 |