Программирование >>  Полное сканирование таблицы 

1 ... 86 87 88 [ 89 ] 90 91 92 ... 107


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

Объедините повторяющиеся запросы в единственный новый запрос.

Слейте повторяющиеся запросы в соединения, которые добавляются к единственному запросу, который уже выполняется приложением.

Перед тем как я рассмотрю эти три решения, возьмем типичный повторяющийся запрос, который получает ценовую историю для данного продукта:

SELECT Product Price FROM Pnce List WHERE Product ID = :1 AND Effect!ve Date <= :today ORDER BY Effective Date DESC:

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

Сколько раз подряд приложению необходимо запустить запрос, чтобы вьшолнить задачу?

Откуда параметры : 1 и : today, на основе которых выполняется запрос, получают свои значения?

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

Каков диапазон количества строк и среднее количество строк, возвращаемое запросом? Какую часть этих строк приложение в действительности использует?

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

Как избежать повторяющихся запросов при помощи кэширования

Если набор возможных значений Prcduct ID невелик по сравнению с тем, сколько раз выполняется запрос в нашем примере, то зто именно тот случай, когда нужно кэшировать весь набор. Например, у нас может быть 10 различных значений Product ID, а запрос повторяется 1000 раз. В этом случае имеет смысл предварительно кэшировать результаты для всего набора и считывать их из кэша, вместо того, чтобы повторно выполнять запросы к базе данных. Например, вы могли бы использовать такой запрос:

SELECT Product Price FROM Price List

WHERE Effective Date <- :today

ORDER BY Product ID ASC. Effect!ve Date DESC:

Полученные результаты могут храниться в кэше - например, в структуре памяти приложения, использующей сегменты хэширования, или в бинарном дереве, которое обеспечивает быстрый (за миллисекунды) доступ к результатам для определенного значения Product ID. Так как количество отдельных операций счи-



тывания в первом варианте превышает количество значений ProductID, второй вариант предлагает два преимущества в терминах стоимости доступа к базе данных.

База данных считывает меньше строк, используя меньше операций логического ввода-вывода. В первоначальном варианте база данных считывает каждую строку в среднем более одного раза, так как в среднем каждое значение ProductID встречается больше одного раза. Эти считывания также были, вероятно, менее эффективными в терминах логического ввода-вывода для каждой строки, так как, скорее всего, они выполнялись путем индексного считывания, а для каждой такой операции требовалось несколько операций логического ввода-вывода. Вариант с предварительным кэшированием, напротив, использует полное сканирование таблицы, при котором одна операция логического ввода-вывода позволяет считать несколько строк.

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

КЭШИРОВАНИЕ В ПРИЛОЖЕНИИ И КЭШИРОВАНИЕ В БАЗЕ ДАННЫХ -

База данных кэширует часто используемые блоки базы данных в собственной совместно используемой памяти, так зачем же создавать еще один кэш прршожения. в котором будут хранться данные, которые, вероятно, уже кэшированы в базе данных? Определенно не для того, чтобы сократить количество операций физического ввода-вывода; оба подхода к кэшированию прекрасно справляются с этой задачей. И все же у кэша приложения есть свои преимущества.

Прежде всего при доступе к нему приложение не генерирует сетевой трафик. Он максимально близок к самому приложению.

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

Цена, которую приходится платить за быстрый кэш приложения, - это увеличенная сложность приложения. Несколько простых статических кэшей для повторно считываемых наборов строк достаточно легко поддерживать, но если вы увлечетесь, то воссоздадите функциональность программного обеспечения базы данных в собственном приложении. В экстремальном случае окажется, что вы используете Oracle, SQL Server или DB2 как простой файловый сервер, хоть и со звучным именем, а ваше приложение будет ответственно за всю работу, которую обычно делает база данных, имея за спиной на порядок меньше разработок, чем в этих базах данных.

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

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



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

Объединенные запросы

Слепой запрос, считывающий все строки, которые потенциально может затронуть повторяющийся запрос, может быть слишком дорогим, и результирующий набор может оказаться слишком большим, чтобы его кэшировать. Однако это не препятствует тому, чтобы приложение объединяло несколько запросов в один запрос в той или другой форме. В нашем примере каждый проход по циклу приносит очередное значение Product ID, на базе которого выполняется исходный повторяющийся запрос. Можно выполнять циклы и без запросов, а просто создать список идентификаторов, чтобы использовать их в одном объединенном запросе. Например, запрос может принимать такие формы:

SELECT Product Price FROM Price List WHERE Product ID in (<дтнный список ID>) AND Effective Date <= :today ORDER BY Product ID ASC. Effective Date DESC:

SELECT Product Price FROM Price List

WHERE Product ID in {<поазапрос. возвращающий длинный список ID>)

AND Effective Date <= :today

ORDER BY Product ID ASC. Effective Date DESC:

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

Слияние повторяющихся запросов с предьщущим запросом

Обычно источником значений параметров в повторяющихся запросах является предьщущий запрос. В нашем примере значение параметра : today скорее всего поступает из часов или календаря, но значение параметра : 1 практически наверняка берется из предьщущего запроса, который вернул длинный список значений Product I D. Самая вероятная причина появления повторяющегося запроса заключается в том, что мы пытаемся получить текущую (с самым недавним значением Effect! ve Date) цену продукта для каждой строки, возвращенной предыдущим запросом, для чего используем первую строку среди тех, которые этот запрос возвращает при каждом



1 ... 86 87 88 [ 89 ] 90 91 92 ... 107

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика