Дизайн приложения и производительность базы данных

Не изменяйте свойство text объекта SQLStatement после его выполнения. Вместо этого используйте отдельные экземпляры объекта SQLStatement для каждой инструкции SQL с различными параметрами инструкций для получения требуемых значений.

Перед выполнением любой инструкции SQL среда выполнения подготавливает ее (компилирует), чтобы определить внутренние действия по выполнению инструкции. При вызове метода SQLStatement.execute() для экземпляра SQLStatement, который до этого не выполнялся, инструкция автоматически подготавливается перед выполнением. При последующих вызовах метода execute() , если свойство SQLStatement.text не изменилось, инструкция все еще является подготовленной. Как следствие, она выполняется быстрее.

Чтобы извлечь максимум выгоды от многократного использования инструкции при необходимости изменять значения в интервалах между выполнением инструкции, используйте параметры инструкции для ее настройки. (Параметры инструкции задаются при помощи свойства ассоциативного массива SQLStatement.parameters .) В отличие от изменения свойства text экземпляра SQLStatement, при изменении значений параметров инструкции среде выполнения не требуется заново подготавливать инструкцию.

Для повторного использования экземпляра SQLStatement приложение должно сохранять ссылку на уже подготовленный экземпляр SQLStatement. Для сохранения ссылки на экземпляр объявите переменную с областью видимости в пределах класса, а не в пределах функции. Для этого рекомендуется структурировать приложение таким образом, чтобы инструкция SQL находилась в оболочке одного класса. Группа инструкций, которые выполняются в комбинации, также может быть заключена в оболочку одного класса. (Эта техника известна как использование шаблона дизайна команды.) За счет определения экземпляров в качестве участвующих переменных класса они продолжают существовать, пока экземпляр класса-оболочки существует в приложении. Можно просто определить переменную, содержащую экземпляр SQLStatement, за пределами функции, чтобы экземпляр оставался в памяти. Например, объявите экземпляр SQLStatement как переменную экземпляра в классе ActionScript или как переменную, не являющуюся функцией, в файле JavaScript. Затем можно задать значения параметров инструкции и вызвать ее метод execute() для выполнения запроса.

Для ускорения выполнения операций сравнения и сортировки данных используйте индексы базы данных.

При создании индекса столбца база данных сохраняет копию данных этого столбца. Эта копия хранится отсортированной в числовом или алфавитном порядке. Сортировка позволяет базе данных быстро сопоставлять значения (например, при использовании оператора сравнения) и сортировать результирующие данные с помощью выражения ORDER BY .

В базе данных всегда поддерживается актуальность индексов, из-за чего немного замедляется выполнение операций изменения данных (INSERT или UPDATE) в этой таблице. Однако может значительно увеличиться скорость извлечения данных. Из-за такого соотношения производительности не следует индексировать каждый столбец в каждой таблице. Вместо этого используйте стратегию определения собственных индексов. Используйте следующий подход для планирования своей стратегию индексирования:

  • Индексируйте столбцы, используемые в таблицах соединения в выражениях WHERE или ORDER BY

  • Если столбцы часто используются вместе, индексируйте их в один файл индекса

  • При индексации столбца, текстовые данные в котором отсортированы по алфавиту, используйте для него сортировку COLLATE NOCASE

Проводите предварительную компиляцию инструкций SQL во время бездействия приложения.

Первое выполнение инструкции SQL производится медленнее, так как механизм базы данных выполняет подготовку (компиляцию) текста SQL. Так как подготовка и выполнение инструкции может быть трудоемкой операцией, одной из стратегий является предварительная загрузка исходных данных и последующее выполнение других инструкций в фоновом режиме:

  1. Сначала загружайте необходимые приложению данные.

  2. По завершении начальных операций по запуску приложения или во время «бездействия» приложения выполняйте другие инструкции.

Предположим, приложению совершенно не требуется обращаться к базе данных для отображения начального экрана. В этом случае дождитесь появления начального экрана, а уже потом открывайте подключение к базе данных. Затем создайте экземпляры SQLStatement и выполните любой из них.

Как вариант, при запуске приложения оно может сразу отображать определенные данные, например результат какого-либо запроса. В таком случае можно выполнить экземпляр SQLStatement для этого запроса. После загрузки и отображения начальных данных создайте экземпляры SQLStatement для других операций базы данных и по возможности выполните другие необходимые инструкции позже.

На практике, при повторном использовании экземпляров SQLStatement дополнительное время, необходимое для подготовки инструкции, используется лишь однократно. Возможно, сильного влияния на общую производительность это не окажет.

Объединяйте несколько операций изменения данных SQL в группу.

Предположим, необходимо выполнить большое количество инструкций SQL, предполагающих добавление или изменение данных (инструкции INSERT или UPDATE ). Можно значительно повысить производительность, выполнив все инструкции в пределах явной транзакции. Если не задать явную транзакцию, каждая инструкция начнет выполняться в собственной автоматически созданной транзакции. По завершении выполнения каждой транзакции (каждой инструкции) среда выполнения записывает полученные данные в файл базы данных на диске.

С другой стороны, рассмотрим ситуацию, когда создается явная транзакция и все инструкции выполняются в контексте этой транзакции. Среда выполнения вносит все изменения в память, затем записывает изменения в файл базы данных одновременно при фиксации транзакции. Запись данных на диск является, как правило, самой трудоемкой частью операции. Следовательно, однократная запись на диск может значительно повысить производительность по сравнению с записью при каждом выполнении инструкции SQL.

Производите обработку объемных результатов запроса SELECT по частям, используя метод execute() класса SQLStatement (с параметром prefetch ) и метод next() .

Предположим, производится выполнение инструкции SQL для получения объемного результата. Приложению необходимо обработать каждую строку данных в цикле. Например, оно форматирует данные или создает из них объекты. Обработка этих данных может занять много времени, что может привести к появлению проблем с рендерингом, например зависанию экрана. Одним из решений является разделение задания на блоки, как описано в разделе « Асинхронные операции ». API-интерфейс базы данных SQL позволяет легко разбивать задачи по обработке данных на части.

Метод execute() класса SQLStatement имеет дополнительный параметр prefetch (первый параметр). Значение этого параметра определяет максимальное количество строк, возвращаемых базой данных до завершения выполнения операции:

dbStatement.addEventListener(SQLEvent.RESULT, resultHandler); 
dbStatement.execute(100); // 100 rows maximum returned in the first set

После получения первого набора данных можно использовать метод next() для возобновления выполнения инструкции и получения следующего набора строк. Подобно методу execute() , метод next() также использует параметр prefetch для определения максимального числа возвращаемых строк:

// This method is called when the execute() or next() method completes 
function resultHandler(event:SQLEvent):void 
{ 
    var result:SQLResult = dbStatement.getResult(); 
    if (result != null) 
    { 
        var numRows:int = result.data.length; 
        for (var i:int = 0; i < numRows; i++) 
        { 
            // Process the result data 
        } 
         
        if (!result.complete) 
        { 
            dbStatement.next(100); 
        } 
    } 
}

Вызывайте метод next() до тех пор, пока не загрузятся все данные. В предыдущем примере кода показано как можно определить, что загружены все данные. Проверьте свойство complete объекта SQLResult, который создается каждый раз при завершении работы метода execute() или next() .

Примечание. Используйте параметр prefetch и метод next() для разделения обработки результирующих данных. Не используйте этот параметр и метод для получения только части результатов запроса. Если необходимо извлечь только подмножество строк в наборе результатов инструкции, используйте выражение LIMIT инструкции SELECT . Если набор результатов выполнения достаточно большой, можно использовать параметр prefetch и метод next() для разделения процесса обработки результатов на части.
Используйте несколько асинхронных объектов SQLConnection с одной базой данных для выполнения нескольких инструкций одновременно.

При подключении объекта SQLConnection к базе данных с использованием метода openAsync() он выполняется в фоновом режиме, а не в основном потоке выполнения среды выполнения. К тому же объект SQLConnection выполняется в фоновом режиме в собственном потоке. При использовании нескольких объектов SQLConnection можно эффективно выполнить несколько инструкций SQL одновременно.

У такого подхода существуют и недостатки. Основным недостатком является то, что для создания дополнительных объектов SQLStatement требуется дополнительная память. Одновременное выполнение нескольких операций также приводит к повышению нагрузки на ЦП, особенно если в системе используется один процессор (или процессор с одним ядром). Принимая во внимание эти недостатки, не рекомендуется использовать этот подход при разработке приложений для мобильных устройств.

Еще одним недостатком является то, что объект SQLStatement связан с одним объектом SQLConnection, поэтому потенциальную выгоду от повторного использования объектов SQLStatement извлечь не удастся. Следовательно, объект SQLStatement невозможно использовать повторно, если он связан с уже используемым объектом SQLConnection.

При использовании нескольких объектов SQLConnection, подключенных к одной базе данных, необходимо помнить, что для выполнения инструкций каждый из них использует собственную транзакцию. Учитывайте эти отдельные транзакции в любом коде, который изменяет данные, например добавляет, изменяет или удаляет данные.

Пол Робертсон (Paul Robertson) создал библиотеку с открытым исходным кодом, которая позволяет извлечь максимум выгоды от использования нескольких объектов SQLConnection, минимизируя потенциальные недостатки этого подхода. Эта библиотека использует пул объектов SQLConnection и управляет связанными объектами SQLStatement. Это гарантирует повторное использование объектов SQLStatement, а также доступность объектов SQLConnection для одновременного выполнения различных инструкций. Для получения дополнительных сведений и загрузки библиотеки посетите веб-сайт http://probertson.com/projects/air-sqlite/ .