Продуктивність додатків для Lotus Notes / Domino 7: частина 1

Одним із самих сумних видовищ є прекрасне додаток, яке повільно настільки, що його не можна використовувати – все довгі години важкої роботи витрачені даремно, тому що користувачі розчаровані повільною реакцією. За останні 12 років ми витратили багато часу на дослідження і тестування Domino-додатків і функціональності, для того щоб зрозуміти, як і де можна оптимізувати продуктивність. Ми почали розробляти та підтримувати Domino-додатки на початку 1990-х років і швидко захопилися продуктивністю. Нам здавалося тоді (і здається до сьогоднішнього часу), що багато чого з того, що ми приймали за проблеми продуктивності сервера, насправді є проблемами продуктивності додатки. І рішення, отже, часто ховаються в додатку, а не на сервері.


У цій серії статей з двох частин ми поділимося з вами деякими своїми знаннями. Дана серія охоплює наступні області продуктивності додатків: властивості бази даних, колекції документів та подання (View). У першій частині ми розглянемо властивості бази даних та колекції документів. У кожному випадку ми виділимо області, які є найбільш важливими, і надамо короткі реальні приклади, для того щоб допомогти вам зрозуміти, що робити у своїх власних додатках Ми будемо використовувати приклади з багатьох додатків. Можливо, ви виявите, що, принаймні, один з них збігається з тим, що ви робите, або з тим, що ви використовуєте. Наша мета полягає в тому, щоб допомогти вам створювати додатки, які є настільки ж швидкими, як і прекрасними.


У даній статті передбачається, що ви маєте досвід розробки додатків для Notes / Domino.


Властивості бази даних


Існує кілька властивостей бази даних, які мають відношення до продуктивності вашої програми.


Don "t maintain unread marks (Не підтримувати мітки нечитаних документів)


Якщо ви відзначите цей прапорець, нечитані документи не будуть відстежуватися в вашому додатку, незалежно від налаштувань, які у вас є для кожного подання. Ми використовували client_clock для контролю часу відкриття бази даних, і те, що ми виявили, дуже нас здивувало. Для великих програм (скажімо, 20GB з 200000 документів) наш Notes-клієнт міг відкрити базу даних приблизно за п'ять секунд без підтримки нечитаних документів, включаючи мережевий трафік. З включеною підтримкою позначок нечитаних документів ми чекали додатково шість і більше секунд. Це додатковий час витрачалося в GET_UNREAD_NOTE_TABLE і RCV_UNREAD. З відключеною підтримкою позначок нечитаних документів ці виклики не виконуються.


У більш маленьких базах даних (менше 1GB) ми виявили економію близько 0.5 секунди з відключеними мітками нечитабельним документів. Звичайно ж, така база даних в порівнянні з великою базою даних відкривається швидше як з включеними мітками нечитаних документів, так і з відключеними. Тому ви повинні вирішити, чи потрібні в вашому додатку мітки нечитаних документів, до того, як ви запустите додаток у виробництво.


Optimize document table map (Оптимізувати карту таблиці документів)


Ця функціональна можливість не змінювалася протягом декількох версій Lotus Notes / Domino. Вона призначена для прискорення індексування подань для додатків зі структурами, що повторюють Domino Directory (іншими словами, вони містять багато документів, що використовують одну форму, і мало документів, що використовують іншу форму; подумайте про документи Person в порівнянні з документами Server в Domino Directory).


Ідея полягає в тому, що замість перевірки примітки кожного документа, для того щоб дізнатися, чи повинен він бути включений в індекс подання, ми здійснюємо два проходи. При першому проході просто перевіряється, пов'язано до цим документом коректне назва форми. На другому проході, при необхідності, перевіряються різні інші умови, які повинні задовольнятися для включення цього примітки документа в індекс подання.


Примітка: В даний час ця функціональна можливість, по-видимому, не покращує час індексації навіть для Domino Directories.


Don "t overwrite free space (Не перезаписувати вільний простір)


Ця функціональна можливість не змінювалася протягом декількох версій Lotus Notes / Domino. Якщо ви знімете позначку з цього прапорця, то при будь-якому видаленні документа Lotus Notes буде дійсно перезаписувати біти даних замість простого видалення посилання на ці дані. Мета цього – зробити дані невідновлювані. Вам бажано використовувати цю функцію тільки в разі побоювання за фізичну збереження вашого жорсткого диска. По суті, для кожного додатка ця додаткова фізичний захист не гарантується і є просто додатковим дією при видаленні даних.


Maintain LastAccessed property (Підтримка властивості LastAccessed)


Ця функціональна можливість не змінювалася протягом декількох версій Lotus Notes / Domino. Якщо ви відзначите цей прапорець, Notes відстежуватиме останнім часом, коли Notes-клієнт відкривав кожен документ в базі даних. Природно, Lotus Notes завжди відстежує час останнього збереження в полі $ UpdatedBy, але ця функція відстежує також і останні читання (однак вона не відслідковує читання Web-браузером).


Ми не зустрічали випадків використання цієї функціональної можливості розробниками, крім як у додатках з базами знань, в яких дані архівуються, якщо вони не читалися певне число місяців або років.


Колекції документів


Ми вже багато років бачимо користувальницький код в агентах, в уявленнях, у формулах полів форми і т.д. Виходячи з нашого досвіду, проблеми продуктивності в клієнтських додатках мають схильність бути більш складними, ніж на сервері, з кількох причин:


Але незалежно від джерела коду, виявляючи, що щось працює повільно, ми починаємо досліджувати код і з певною часткою ймовірності знаходимо такі спільні моменти:


Виконуючи тестування протягом багатьох років, ми виявили, що, звичайно, перший крок є дуже швидким і не потребує оптимізації, принаймні, поки немає більш об'ємних завдань. Третій крок часто повільний, але, на жаль, він не дуже гнучкий. Тобто, малоймовірно, що ви виявите, що ваш код неефективний при читанні інформації або збереження її в набір документів. Наприклад, намагаючись зберегти поточну дату в полі DateToday, ви, ймовірно, використовували б один з наступних методів:


Розширений клас


Set Doc = dc.getfirstdocument
Do while not (Doc is Nothing)
Doc.DateToday = Today
Call Doc.Save
Set Doc = dc.getnextdocument ( Doc )
Loop

ReplaceItemValue


Set Doc = dc.getfirstdocument
Do while not (Doc is Nothing)
Call Doc.ReplaceItemValue (“DateToday”, Today)
Call Doc.Save
Set Doc = dc.getnextdocument (Doc)
Loop

StampAll


Call dc.StampAll (“TodayDate”, Today)

У наших тестах ми ніколи не бачили відмінностей в продуктивності між першими двома з трьох наведених вище процедур. Використання розширеного синтаксису класу doc.DateToday = Today здається таким же швидким, як і використання doc.ReplaceItemValue ("DateToday", Today). Теоретично, ми повинні були б побачити деяка відмінність у продуктивності, оскільки в одному випадку ми не явно вказуємо Lotus Notes, що будемо оновлювати елемент поля, тому Lotus Notes повинен був би витратити трохи більше часу, визначаючи, що DateToday насправді є полем. Однак практичні тести не показують відмінностей.


Метод dc.StampAll швидше, якщо ви оновлюєте багато документів з одним значенням, як у попередньому прикладі. Існували деякі проміжні версії, в яких програмна помилка робила даний метод значно повільнішим, тому, якщо ви не використовуєте все саме нове і краще, переконайтеся, що він працює оптимально (або шляхом тестування, або шляхом перевірки списку виправлень). У Lotus Notes / Domino 6.5 і 7 цей метод знову працює швидко. Однак існує так багато перевірок, що виконуються з даними або змінними даними для запису у документи, що dc.StampAll не завжди життєздатний. Ми відносимо його до категорії цінної інформації, яку ви в деяких випадках можете використовувати в конкретному додатку, а в деяких немає.


При рішенні, на якому ж із трьох методів ми повинні були б зупинитися, наш досвід підказує, що таким методом є ReplaceItemValue (одержання колекції документів). Виявляється, що він часто є найтривалішим за часом ділянкою коду, але, на щастя, найбільш стисливим. Йому ми приділяли основну увагу при тестуванні, і саме його будемо розглядати до кінця даного розділу.


Тестування


Технологія нашого тестування полягала у створенні великої бази даних з документами приблизно однакового розміру (близько 2K) і з однаковою кількістю полів (приблизно 200). Ми встановлювали в документах деякі ретельно запрограмовані відмінності, для того щоб ми могли виконувати пошук будь-якої кількості документів. Зокрема, ми налаштовували документи так, щоб ми могли шукати 1, 2, 3, … 9, 10 документів, а також 20, 30, 40, … 90, 100; і 200, 300, 400, … 900, 1000 і т.д. Це давало нам величезну кількість інформаційних точок і дозволяло перевіряти, чи не отримуємо ми хорошу продуктивність лише для вузького набору умов. Наприклад, db.search є відмінним виконавцем при великому підмножині документів у базі даних, але поганим виконавцем при маленькому підмножині. Без ретельного тестування на всьому спектрі умов, ми могли б бути введені в оману щодо характеристик продуктивності.


Ми запускали тести на тривалий час, записуючи результати в текстові файли, які потім могли б імпортувати в електронні таблиці та презентаційні програми для відображення в поданні двовимірних графіків. Після безлічі таких ітерацій і після роботи як з маленькими базами даних (10 тисяч документів), так і з великими (4 мільйони документів), ми прийшли до певних висновків, які, сподіваємося, будуть корисні розробникам додатків.


Які методи найшвидші?


Найшвидшим методом отримання колекції документів для читання або запису є використання або db.ftsearch, або view.GetAllDocumentsByKey. Виявляється, що інші методи (дивіться список нижче) можуть бути близькі до них за швидкістю (для деяких наборів документів, розглянутих нижче), але жоден з них не може порівнятися з цими методами одночасно для маленьких і для великих колекцій. Тут ми перерахуємо методи і наведемо коротке пояснення, а розглянемо їх більш докладно пізніше.


Якщо у вас є невелика колекція документів (наприклад, 10) і маленька база даних (наприклад, 10000 документів), різні методи будуть показувати приблизно однакову продуктивність, і всі вони будуть дуже швидкими. Це можна було б назвати тривіальним випадком, і якщо цей код не виконується повторно багато разів (або не часто використовується у вашому додатку), ви можете залишити його недоторканим і перейти до більш насущних проблем.


Однак ви все одно можете знайти невеликі відмінності, і якщо вам потрібно отримувати багато колекцій документів, то навіть економія частки секунди при кожному виконанні вашого коду буде мати значення. Крім того, якщо ваш додаток велике (чи зростає), ви побачите, що відмінності в часі стають основним питанням!


Наведемо два користувальницьких прикладу: перший – заплановані агенти (scheduled agents), налаштовані на дуже часте виконання (кожні кілька хвилин або при будь-якому записі або при будь-якому оновленні документів) і виконують ітерацію по кожному новому документу для отримання критерію пошуку та подальшого виконання операцій пошуку на основі цього критерію. Якщо обробляється 10 нових документів, виконується 10 операцій пошуку, а якщо обробляється 100 нових документів, виконується 100 операцій пошуку. У цьому випадку, якщо б ми могли заощадити 0.5 секунди при отриманні колекції документів, реальна економія була б дорівнює добутку 0.5 на 10 або 100, множилася далі на кількість виконань агента. Можна було б легко заощадити багато хвилини в кожному годині в періоди великого завантаження, що істотно. Інший приклад – головна форма має подія PostOpen або QuerySave, яке виконує цей код. Якщо у вас відбуваються сотні редагувань на годину (або більше), ці 0.5 секунди економії помножаться до помітного результату.


За і проти кожного методу


Пояснюючи колегам або користувачам, чому деякі з цих методів швидше або простіше, ніж інші, ми часто бували залучені в жваві дискусії, повні аргументів "з одного боку" і "з іншого боку". До наше глибоке задоволення, чим глибше ми занурювалися в ці аргументи, тим ясніше ставали проблеми. Ми спробуємо привнести це пожвавлення в дану статтю за допомогою двох міфічних сперечаються опонентів, Прометеус (Prometheus, для друзів просто "Pro") і його колеги скептичного Конні (Connie, або просто "Con").


Prometheus: view.GetAllDocumentsByKey виглядає дуже швидким. Я вирішив радити використовувати його скрізь, де тільки можливо.


Connie: Чудово, мій друг, але що якщо ви шукаєте дані в Domino Directory? Ви не зможете легко отримати дозвіл створити там нові вистави.


Pro: Згоден. Добре, я буду використовувати цей метод у додатках, де я контролюю пошукову базу даних.


Con: Так? А якщо вам доведеться створити 10 додаткових уявлень в базі даних, чи буде цей метод також хороший? Подумайте про всі необхідні додаткові індексація уявлень.


Pro: Це, можливо, здасться дивним, але якщо я створюю оптимізовані уявлення, вони, ймовірно, індексуються менш ніж за 100 мілісекунд кожні 15 хвилин при виконанні завдання UPDATE – більше, якщо потрібно операціями пошуку. Невже ми не можемо пожертвувати кілька сотень мілісекунд кожні кілька хвилин?


Con: Як спростити ці уявлення? Чи складно це? Скільки буде потрібно роботи з обслуговування?


Pro: Нічого страшного. Для оптимізації пошукового подання (lookup view) спочатку максимально оптимізується критерій вибору. Це зменшує розмір індексу представлення і, отже, час оновлення індексу та виконання операцій пошуку. Тепер подумайте про те, як будете виконувати пошук з цим поданням. Якщо ви збираєтеся отримувати всі документи, розгляньте використання одного відсортовані стовпця з формулою "1". Тоді отримання всіх документів в уявленні є тривіальним завданням. Якщо необхідні різні поля з інформацією, подумайте про створення другого стовпця, що об'єднує ці дані в одну операцію пошуку. Одна операція пошуку набагато швидше декількох, навіть якщо обсяг отримуваних даних однаковий.


Con: Добре, можливо, ви мене переконали. Але є db.ftsearch, розрекламований як дуже швидкий, але я не впевнений, що готовий використовувати цей метод. Таке враження, що для нього необхідна велика інфраструктура.


Pro: Це правда, використання db.ftsearch в коді виправдано. Але необхідно, по-перше, підтримувати повнотекстовий індекс і, по-друге, конфігурація сервера Domino повинна включати FT_MAX_SEARCH_RESULTS = n, де n – це число, більше максимального розміру колекції, яка повинна повертатися для вашого коду. Без цього ви обмежені 5000 документами.


Con: А що станеться, якщо повнотекстовий індекс не оновлюється дуже швидко?


Pro: У цьому випадку ваш код може містити виклик db.UpdateFTIndex для оновлення індексу.


Con: Моє тестування показує, що це може бути досить тривала за часом операція, і цей час набагато перекриє всі переваги в продуктивності, одержувані від використання db.ftsearch. І що відбудеться, якщо повнотекстовий індекс так і не був створений?


Pro: Якщо база даних має менше 5000 документів, тимчасовий повнотекстовий індекс буде створюватися "на льоту" за вас.


Con: З цим є дві проблеми. По-перше, тимчасове повнотекстовий індекс дуже неефективний, тому що він створюється після запуску коду. По-друге, 5000 документів – не дуже високий поріг. Схоже, що це могли б бути лише деякі поштові файли в моїй організації. Що якщо в базі даних є понад 5000 документів?


Pro: У цьому випадку використання using db.UpdateFTIndex (True) створить постійний повнотекстовий індекс.


Con: Добре, але створення повнотекстового індексу для великих баз даних може бути дуже тривалої за часом процедурою. Я також знаю, що повнотекстовий індекс буде створюватися лише для локальної бази даних, тобто, розташованої на тому ж сервері, що і що виконується код.


Pro: Абсолютно вірно. На щастя, Lotus Notes / Domino 7 має поліпшений вивід на консоль, а також має здатність використовувати Domino Domain Monitoring (DDM) для більш точного відстеження таких проблем, як використання методів ftsearch з базами даних, що не мають повнотекстового індексу. Ось пара повідомлень, які ви можете отримати в консолі. Як бачите, вони досить зрозумілі:


Agent Manager: Full text operations on database “xyz.nsf” which is not full text indexed. This is extremely inefficient.
mm / dd / yyyy 4:04:34 PM Full Text message: index of 10000 documents exceeds limit (5000), aborting: Maximum allowable documents exceeded for a temporary full text index

Con: Я помітив, що ви до цих пір не сказали нічого позитивного про view.ftsearch, view.GetAllEntriesByKey або db.search. Мені здається, я знаю, чому. Перші два в певних умовах працюють швидко, але, якщо подання структуровано так, що пошукові дані проіндексовані ближче до кінця вистави, вони можуть бути дуже повільними. А db.search дуже ефективний для маленьких колекцій документів.


Pro: Все вірно. Однак db.search дуже ефективний для операцій пошуку за часом / датою, в яких ви не хочете створювати уявлення з формулами часу / дати і підтримувати повнотекстовий індекс для використання методу db.ftsearch. Також, якщо ви виконуєте пошук в базах даних, які ви не контролюєте, і якщо ці бази даних ще не мають повнотекстового індексу, можливо, що db.search – це ваш єдиний реальний варіант отримання колекції документів.


Наведемо кілька діаграм, які допоможуть зрозуміти наведені вище твердження, висловлені Pro. Ці діаграми показують час всього лише отримання колекції документів. Ніякого читання з цих документів не проводиться, і нічого в них не записується. Це тестове додаток в нашій тестовій середовищі, тому абсолютні значення повинні сприйматися критично. Однак співвідношення різних методів повинні узгоджуватися з тим, що ви могли б знайти у вашій власній середовищі.


На малюнку 1 db.ftsearch і view.GetAllDocumentsByKey, фактично, не відрізняються один від одного, обидва є найкращим вибором. Назвемо це нічиєї в боротьбі за перше місце. Третім (дуже близьким до лідерів) був би view.GetAllEntriesByKey, в той час як view.ftsearch починає виконуватися дуже добре, але потім швидко погіршує результати при досягненні кількості документів близько 40.


Малюнок 1. Колекції документів, оптимізовані подання (до 100 документів)

Малюнок 2 незначно відрізняється від малюнка 1 в тому, що db.search шукає все краще і краще в міру збільшення кількості документів. Виявляється, що при збільшенні розміру колекції з 5 до 10 відсотків всіх документів у базі даних, db.search буде також швидкий, як і лідери. А, як ми бачили на малюнку 1, view.ftsearch при збільшенні розмірів колекції працює все гірше і гірше.


Малюнок 2. Колекції документів, оптимізовані подання (від 100 до 1000 документів)

На малюнку 3 уявлення більше не оптимізовані на розміщення результатів ближче до початку вистави. Тобто, якщо ми отримуємо колекцію лише невеликого числа документів у порівнянні з нашою тестовою середовищем, то можемо спробувати змінити результати так, щоб ці кілька документів були розташовані ближче до початку або до кінця пошукового подання. На малюнках 1 і 2 ці документи були розташовані ближче до початку вистави, але на малюнку 3 вони розташовані ближче до кінця. Для трьох з наведених вище методів це не важливо (db.search, db.ftsearch і view.GetAllDocumentsByKey). Однак для view.ftsearch і view.GetAllEntriesByKey таке перемикання катастрофічно в сенсі показників продуктивності. Масштаб малюнків 2 і 3 необхідно змінити – по осі Y замість однієї секунди потрібно встановити шість секунд!


Малюнок 3. Колекції документів, не оптимізовані подання

Висновок


Коли це можливо, використовуйте view.GetAllDocumentsByKey для отримання колекції документів. Разом з цим оптимізуйте ваші пошукові подання так, щоб вони були максимально простими і ефективними. У другій частині даної серії статей даються деякі поради по цій темі.


Якщо ваш пошук повинен виконуватися за форматованим текстовим (rich text) полів, або ваша база даних вже має повнотекстовий індекс, db.ftsearch є відмінним вибором, і його варто використовувати. Ваші результати завжди повинні містити менше 5000 документів, інакше використовуйте параметр Notes.ini FT_MAX_SEARCH_RESULTS = n (де n – це максимальне число повертаються документів), щоб гарантувати виключення можливості втрати цілісності ваших даних з-за цього обмеження.


Цим завершується перша частина нашого дослідження продуктивності додатків для Notes / Domino 7. У другій частині ми розглянемо, як можна створювати високопродуктивні подання. До зустрічі!

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*