Всім привіт
Сьогодні попросили мене при друку документа реалізації не виводити префікс документа, завдання вирішив наступним чином.

СтрЗаменіть (Номер, Лев (Номер, 3), "");

Коли заглянув в синтаксис-помічник так мені це сподобалося, що захотілося написати про роботі з рядками в «1С: Підприємство».

Рядок в 1С відноситься до примітивного типу даних.

Якщо подивитися в довідку 1С побачимо наступний опис типу Рядок (String)
значення даного типумістять рядок у форматі Unicode довільної довжини.
Якщо своїми словами про рядках то вийде. Рядок - константа, що складається з різних символів, оточеного завжди лапками.

завдання рядки
Звернення = «Привіт пасажир»;

Багаторядкові рядки в типових конфігураціях найчастіше створюються за допомогою вертикального роздільник «|»:
Рядок = "багаторядкова
| рядок
| пиши
| Текст »;

Лапки усередині рядка задаються подвійними лапками.
Рядок = "" Текст в лапках »»;

Над рядками існує безліч операцій (пошук в нутрії рядки, визначення перших і т.д.), краще подивитися Синтакс-помічник.
Синтакс-помічник - Загальний описвбудованого мови-> вбудовані функції-> функції по роботі з рядками.

Функцій по роботі з рядками

Тут в стислій формі приведу функцій по роботі з рядками:

ВРег (<Строка>) - Все символи рядка функція перетворює в верхній регістр.

КодСімвола (<Строка>, <НомерСимвола>) - Функція отримує код символу, розташованого в переданої рядку в позиції з зазначеним номером.

Лев (<Строка>, <ЧислоСимволов>) - Функція вибирає перші зліва символи рядка.

знайти (<Строка>, <ПодстрокаПоиска>) - Функція знаходить входження шуканого рядка як підрядка в заданій стрічці.

НРег (<Строка>) - Функція перетворює всі символи рядка в нижній регістр.

прав (<Строка>, <ЧислоСимволов>) - Ця функція відрізняється від функцій Лев (Left) тим що вибирає останні праворуч символи рядка.

Порожня стрічка(<Строка>) - Функція перевіряє рядок на наявність значущих символів.

символ (<КодСимвола>) - Функція перетворює код символу в рядок, що містить символ.

СокрЛ (<Строка>) - Функція відсікає незначні символи, які стоять зліва від першого значущого символу в рядку.

СокрЛП (<Строка>) - Функція відсікає незначні символи, які стоять зліва від першого значущого символу в рядку, і прогалини, які стоять праворуч від останнього значущого символу в рядку.

СокрП (<Строка>) - Функція відсікає незначні символи, які стоять праворуч від останнього значущого символу в рядку.

середовищ (<Строка>, <НачальныйНомер>, <ЧислоСимволов>) - Функція вибирає рядок символів, починаючи з символу<НачальныйНомер>, Загальною кількістю<ЧислоСимволов>.

СтрДліна (<Строка>) - Функція отримує кількість символів в рядку.

СтрЗаменіть (<Строка>, <ПодстрокаПоиска>, <ПодстрокаЗамены>) - Функція знаходить в заданій стрічці все входження підрядка пошуку і замінює її на подстроку заміни.

СтрПолучітьСтроку (<Строка>, <НомерСтроки>) - Функція отримує рядок многострочной рядки по номеру.

СтрЧіслоВхожденій (<Строка>, <ПодстрокаПоиска>) - Функція обчислює число входжень підрядка пошуку в заданій стрічці.

СтрЧіслоСтрок (<Строка>) - Функція вважає число рядків в многострочной рядку. У многострочной рядку, рядки розділені символами переведення рядків.

Трег (<Строка>) - Функція перетворює рядок до титульного регістру. Це означає, що у кожного слова перший символ перетворюється до титульного регістру або до верхнього регістру, якщо титульний регістр для символу не визначений. Решта символів перетворюються до нижнього регістру.

перетворення типів
Для явного перетворення типів даних існують функції однойменні з типом даних, до якого відбувається перетворення: Рядок (<Значение>)

СтрокаІзЧісел = Рядок (Число);

Всі ці функції докладно описані в Синтакс-помічник, як починаючому програмісту може допомогти Синтакс-помічник, я описав у статті.

Приклади по роботі з рядками

Перетворення числа в рядок і назад.

Для отримання строкового подання року слід використовувати функцію Формат.

Рік = Формат (ТекущаяДата (), "ДФ = yyyy") // Рік = "2012"

Щоб перетворити число до рядка без вставки символу-роздільника груп (нерозривного пробілу), необхідно застосувати функцію Формат з параметром ЧГ = 0:

Число = 2012 Рядок = Формат (Число, "ЧГ = 0"); // Рядок = "2012"

Рядок Без пробілів.

Механізмів для роботи з рядками в запитах 1С мало. По-перше, рядки можна складати. По-друге, від рядка можна взяти подстроку. По-третє, рядки можна порівнювати, в тому числі за шаблоном. Ось мабуть і все, що можна робити з рядками.

додавання рядків

Для складання рядків в запиті використовується операція «+». Складати можна тільки рядки обмеженої довжини.

ВИБРАТИ "Найменування:" + Контрагенти.Наіменованіе ЯК Колонка1 З Справочнік.Контрагенти ЯК Контрагенти ДЕ Контрагенти.Ссилка = & Посилання

функція Підрядок

підрядки (<Строка>, <НачальнаяПозиция>, <Длина>)

Аналог функції Серед () з об'єктної моделі. Функція Підрядок () може застосовуватися до даних строкового типу і дозволяє виділити фрагмент <Строки> , Що починається з символу номер <НачальнаяПозиция> (Символи в рядку нумеруються з 1) і довжиною <Длина> символів. Результат обчислення функції має строковий тип змінної довжини, причому довжина буде вважатися необмеженої, якщо <Строка> має необмежену довжину і параметр <Длина> не є константою або перевищує 1024.

Якщо довжина рядка менше, ніж вказана в другому параметрі, то функція поверне порожній рядок.

Увага!Використання функції Підрядки () з метою приведення рядків необмеженої довжини до рядків обмеженої довжини не рекомендується. Замість неї краще використовувати операцію приведення типу ВИРАЗИТИ ().

функція Подібно

Якщо потрібно переконатися, що строковий реквізит відповідає певним критеріям ми його порівнюємо:

ВИБРАТИ Контрагенти.Наіменованіе ЯК Колонка1 З Справочнік.Контрагенти ЯК Контрагенти ДЕ Контрагенти.Наіменованіе = "Газпром"

А що, якщо потрібно більш хитре порівняння? Не просто на рівність чи нерівність, а на подобу певним шаблоном? От саме для цього і створена функція ПОДІБНО.

ПОДІБНО - Оператор перевірки рядка на подобу шаблоном. Аналог LIKE в SQL.

Оператор ПОДІБНО дозволяє порівняти значення виразу, вказаного ліворуч від нього, з рядком шаблону, зазначеної справа. Значення виразу повинне мати тип рядок. Якщо значення виразу задовольняє шаблоном - результатом оператора буде ІСТИНА, інакше - БРЕХНЯ.

Наступні символи в рядку шаблону є службовими і мають сенс, відмінний від символу рядка:

  • % (Відсоток): послідовність, що містить будь-яку кількість довільних символів;
  • _ (Підкреслення): один довільний символ;
  • [...] (в квадратних дужкаходин або кілька символів): будь-який одиночний символ з перерахованих всередині квадратних дужок. У перерахуванні можуть зустрічатися діапазони, наприклад a-z, які означають довільний символ, що входить в діапазон, включаючи кінці діапазону;
  • [^ ...] (в квадратних дужках значок заперечення, за яким слід один або кілька символів): будь-який одиночний символ, крім тих, які перераховані слідом за значком заперечення.

Будь-який інший символ означає сам себе і не несе ніякого додаткового навантаження. Якщо в якості самого себе необхідно записати один з перерахованих символів, то йому повинен передувати<Спецсимвол>. сам<Спецсимвол>(Будь-який відповідний символ) визначається в цьому ж операторі після ключового словаСпецсимволи.

Головна Нотатки із Задзеркалля

07.02.2013 Пошук по рядку

Реалізовано в версії 8.3.3.641.

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

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

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

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

Наприклад, ви можете вказати, що пошук буде виконуватися в будь-якому місці рядка, а не тільки в її початку:

Тоді користувач може набирати будь-які фрагменти слів, а не тільки ті символи, з яких починається шукана стрічка:

Використання повнотекстового пошуку при введенні по рядку включається окремим властивістю:

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

Також вони можуть шукати і по кільком відомим словам. Незакінчені слова будуть автоматично доповнюватися можливими поєднаннями:

Якщо обсяг даних великий, то в обох випадках ви можете вказати, що пошук повинен виконуватися за допомогою фонового завдання:

Тоді поруч з полем введення для користувачів буде відображатися анімована картинка, схожа на картинку, яка відображається при фоновому режимі звіту:

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

Всі перераховані властивості ви можете, при необхідності, перевизначити в процесі виконання прикладного рішення.

На клієнті - в клієнтських обробниках подій поля введення автодобір і ОкончаніеВводаТекста :

На сервері - в модулі менеджера того об'єкта, в даних якого виконується пошук. У обробнику події ОбработкаПолученіяДаннихВибора :

Природно, в цьому місці, на сервері, не можна перевизначити спосіб виконання пошуку "Безпосередньо" або "Фоновим завданням" . Тому що виконання коду вже передано на сервер.

Рядок - один з примітивних типів даних в системах 1С: Підприємство 8. Змінні з типом рядокмістять текст.

Значення змінних типу рядокполягають в подвійні лапки. Кілька змінних даного типу можна складати.

Пер1 = "Слово 1";
Пер2 = "Слово 2";
Пер3 = Пер1 + "" + Пер2;

В підсумку Пер3матиме значення « Слово 1 Слово 2 ".

Крім того, в системах 1С: Підприємство 8 передбачені функції для роботи з рядками. Розглянемо основні:

ВвестіСтроку (<Строка>, <Подсказка>, <Длина>, <Многострочность>) — функція призначена для виведення діалогового вікна, в якому користувач може вказати значення змінної типу рядок. параметр <Строка> є обов'язковим і містить ім'я змінної, в яку буде записана введений рядок. параметр <Подсказка> необов'язковий - це заголовок діалогового вікна. параметр <Длина> необов'язковий, показує максимальну довжинувведеної рядки. За замовчуванням дорівнює нулю, що означає необмежену довжину. параметр <Многострочность> необов'язковий. Визначає режим введення багаторядкового тексту: Істина - введення багаторядкового тексту з роздільниками рядків; Брехня - введення простий рядки.

Рядок можна ввести і, знаючи код символу в кодуванні Unicode:

символ (<КодСимвола>) — код вводиться у вигляді числа.

Буква = Символ (1103); // Я

Існує і зворотна функція, що дозволяє дізнатися код будь-якого символу.

КодСімвола (<Строка>, <НомерСимвола>) — повертає номер зазначеного символу в кодуванні Unicode у вигляді числа.

Функції перетворення регістру тексту:

ВРег (<Строка>) - перетворює всі символи рядка в верхній регістр.

НРег (<Строка>) - перетворює всі символи рядка в нижній регістр.

Трег (<Строка>) - перетворює всі символи рядка в титульний регістр. Тобто перші літери у всіх словах перетворюється в верхній регістр, а інші літери - в нижній.

Функції пошуку і заміни символів в рядку:

знайти (<Строка>, <ПодстрокаПоиска>) - знаходить номер символу входження підрядка пошуку. наприклад:

Знайти ( "Рядок", "ока"); // 4

СтрНайті (<Строка>, <ПодстрокаПоиска>, <НаправлениеПоиска>, <НачальнаяПозиция>, <НомерВхождения>) - знаходить номер символу входження підрядка пошуку, номер входження вказується у відповідному параметрі. При цьому пошук починається з символу, номер якого вказаний у параметрі НачальнаяПозіція.Пошук можливий з початку або з кінця рядка. наприклад:

Номер4 Входження = СтрНайті ( "Обороноздатність", "О", НаправленіеПоіска. Спочатку, 1, 4); // 7

СтрЗаменіть (<Строка>, <ПодстрокаПоиска>, <ПодстрокаЗамены>) - знаходить в заданій стрічці все входження підрядка пошуку і замінює її на подстроку заміни.

СтрЗаменіть ( "Рядок", "ока", ""); // Стор

Порожня стрічка(<Строка>) - перевіряє рядок на наявність значущих символів. Якщо значущих символів немає, або взагалі ніяких символів немає, то повертається значення істина. В іншому випадку - брехня.

СтрЧіслоВхожденій (<Строка>, <ПодстрокаПоиска>) - обчислює число входжень підрядка пошуку в заданій стрічці.

СтрЧіслоВхожденій ( "Вчитися, вчитися і ще раз вчитися", "Вчитися", ""); // 3

СтрШаблон (<Строка>, <ЗначениеПодстановки1>…<ЗначениеПодстановкиN> — підставляє параметри в рядок за номером. Рядок повинен містити маркери підстановки виду: «% 1 ..% N». Нумерація маркерів починається з 1. Якщо значення параметра Не визначене, Підставляється порожній рядок.

СтрШаблон ( "Параметр 1 =% 1, Параметр 2 =% 2", "1" , "2" ) ; // Параметр 1 = 1, Параметр 2 = 2

Функції перетворення рядків:

Лев (<Строка>, <ЧислоСимволов>) - повертає перші спочатку символи рядка.

прав (<Строка>, <ЧислоСимволов>) - повертає останні символирядки.

середовищ (<Строка>, <НачальныйНомер>, <ЧислоСимволов>) - повертає рядок довжиною в<ЧислоСимволов>, Починаючи з символу<НачальныйНомер>.

СокрЛ (<Строка>) відсікає незначні символи, які стоять зліва від першого значущого символу в рядку.

СокрП (<Строка>) - відсікає незначні символи, які стоять праворуч від останнього значущого символу в рядку.

СокрЛП (<Строка>) - відсікає незначні символи, які стоять зліва від першого значущого символу в рядку і праворуч від останнього значущого символу в рядку.

СтрПолучітьСтроку (<Строка>, <НомерСтроки>) - отримує рядок многострочной рядки по номеру.

Інші функції:

СтрДліна (<Строка>) - повертає кількість символів в рядку.

СтрЧіслоСтрок (<Строка>) - повертає число рядків в многострочной рядку. Рядок вважається новою, якщо вона відокремлена від попередньої символом переведення рядка.

СтрСравніть (<Строка1>, <Строка2> ) - порівнює два рядки без урахування регістру. Функція працює аналогічно об'єкту СравненіеЗначеній. повертає:

  • 1 - якщо перший рядок більше другий
  • -1 - якщо другий рядок більше першої
  • 0 - якщо рядки рівні

СтрСравніть ( "Перший рядок", "Другий рядок"); // 1

Мене звуть Павло Баркет, я працюю в компанії «Софтпоінт». Ми вже більше 10 років займаємося вирішенням завдань оптимізації продуктивності. І незважаючи на велику кількість вирішених завдань, їх кількість не зменшується, а зростає в геометричній прогресії. Обсяги даних збільшуються, і завдання по оптимізації роботи з цими даними ускладнюються. Цей процес неминучий.

Тема статті - нетривіальні підходи до оптимізації. будуть розглянуті два аспекти:

  • перший - пошук по підрядку. Користувачі часто його використовують, і багато хто, напевно, вже стикалися із значним очікуванням, пошук по підрядку виконується недостатньо швидко.
  • другий - проведення великих документів, Таких, як закриття місяця, розрахунок собівартості. Напевно багато хто стикався з тим, що бухгалтери проводять ці документи по 5-9 годин, вночі і в неробочий час. Найцікавіше, що класичні методи оптимізації тут не завжди допомагають. Якщо ви при проведенні таких документів запустіть в отладчике завмер продуктивності, то побачите, що найбільша кількість часу витрачається на запис в тимчасові або реальні структури - таблиці, регістри і т.д. І вирішити цю задачу класичними методами не виходить.

Пошук по підрядку

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

Пошук за початковими символам

Почну з першого прикладу, коли пошук здійснюється за початковими символам. Це - окремий випадок пошуку по підрядку, коли користувач точно знає, що шукане значення починається з певних символів.

Пошук за початковими символам реалізується в 1С за допомогою команди ПОДІБНО(Або в англійському варіанті, LIKE) із зазначенням значення з «%» в кінці ( «%» позначає послідовність будь-яких інших символів). Наприклад, ми шукаємо:

Найменування ПОДІБНО "івано%"

Зверніть увагу, що якщо у вас в системі існує індекс по цьому полю, то в SQL-запиті для цього пошуку буде використовуватися Index Seek- це пошук за індексом.

Умова «ПОДІБНО пошуковому рядку»Еквівалентно пошуку в діапазоні значень. В окремому випадку, коли ми шукаємо «івано%» - це еквівалентно пошуку в діапазоні прізвищ, які починаються на «івано», і, закінчуючи «іванп» (тому що символ «п» йде після символу «о»).

Сучасні оптимізатори самостійно перетворять запит LIKE на запит пошуку по діапазону. Отже, якщо у вас в системі існує індекс по цьому полю, ви при інтерпретації запиту в терміни SQL отримаєте саме такий результат - оптимізатор представить запит з LIKE у вигляді пошуку по діапазону.

Таким чином, можна здійснювати класичний швидкий пошук з використанням індексу (Index Seek). З цим проблем немає або вирішити їх можна простим способом.

Пошук по входженню

Тепер візьмемо приклад складніше, коли невідомо, в якому саме місці рядка стоїть наше шукане значення, і реалізується пошук по входженню рядки. В цьому випадку в запиті «ПОДІБНО» «%» варто з двох сторін.

При перетворенні такого запиту в SQL ми бачимо, що змінюється тільки команда (в значенні використовується вже два «%»).

Розглянемо докладніше план виконання. тут ми бачимо той же Index Seek, але в даному випадку він не працює ефективно.

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

  • Перше з них - це роздільник обліку.
  • Далі безпосередньо йде поле пошуку.

І тому, коли в плані виконання відображається «Index Seek», це означає, що пошук робиться по першому полю роздільник- на слайді вище можна побачити, що пошук по нашому згаданої значенням Desc абсолютно не використовується.

Що робити в цій ситуації? У мене на практиці було дуже часто, що користувачам забороняли використовувати запити на входження. І користувачі в ряді випадку самі не використали цей функціонал, тому що час виконання дуже значне, а треба продовжувати працювати. Тому їм доводилося викручуватися іншими способами - вибирали в списках, намагалися знайти по перших символах і так далі.

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

Нетривіальний підхід до вирішення завдання пошуку по підрядку

Давайте тепер розглянемо нетривіальний підхід до вирішення цього завдання.

Позначимо ряд допусків:

  • Перше - оскільки сучасні диски мають необмежений розмір, Припустимо, що простір на диску, яке ви можете використовувати, у вас є достатньо велика.
  • Друге - користувач шукає не по одному-двом символам, а по якомусь фрагменту. Наприклад, ніхто з нас не шукає по «ал» - це занадто маленька селективність. Шукають якусь значиму послідовність символів. Тут ми для прикладу вибрали пошук по шести символів.

Приклад шуканої рядка «Алекс» записали в форму і будемо з її допомогою тестувати.

  • Припустимо, у нас є поле з прізвищем, ім'ям та по батькові клієнта. Першим кроком ми автоматично розкладаємо це значення на фрагменти з шести символів зі зрушенням «1»і отримуємо масив фрагментів (див. вище), які одночасно завжди належать згаданої значенням. Ми отримали фрагменти, які теоретично може вводити користувач. А саме, на минулому слайді визначили, що ми шукаємо шість символів. Їх може бути і п'ять, і чотири, просто розмір структури буде більше.

  • На другому кроці ми записуємо ці набори в окрему структуру(Це може бути таблиця, регістр відомостей і т.д.) і отримуємо вибірку, в якій певний фрагмент належить різним значенням.

  • І на третьому кроці, ми при пошуку по підрядку до конструкції запиту 1С «ПОДІБНО» додаємо додаткову умову «І», яке фільтрує кількість можливих комбінацій, і витягуємо з цієї додаткової структури (це може бути регістр відомостей) всі елементи, яким належать потрібні фрагменти рядків.

Наприклад, користувач шукає клієнта з прізвищем «Солдатов». Це - вісім символів, значить, буде три фрагмента довжиною в шість символів, які ми шукаємо в службовій структурі. Далі об'єднуємо це все в запиті. Таким чином, виходить додаткова фільтрація.

В результаті ми позбавляємося від знака «%» (тобто попереду цих фрагментів завжди буде потрібний нам символ), і при виконанні внутрішнього запиту буде йти Index Seek, за який ми і боролися.

На практиці виходить дуже цікава історія - прискорення в десятки, в сотні разів. Причому, все це можна зробити засобами 1С, що дуже приємно. Переписувати логіку не буде потрібно, користувач буде радіти, що у нього прискорився запит пошуку. У прикладі прискорення з 4 секунд до 0,05 секунди, а якби у нас спочатку запит виконувався дві хвилини, він став би виконуватися менше секунди.

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

Підготовчі заходи для впровадження

Тепер я розповім коротко про підготовчі заходи.

  • спочатку необхідно заповнити реєстр початковими значеннями. Для цього ми повинні запланувати регламентне вікно.
  • Далі ми повинні дотримати консистентность даних - це значить, повинна бути підписка на зміну значення, Щоб ця Фрагменти автоматично перебудовувалися.
  • І останнє - дописати стандартну форму пошуку.

Заповнення реєстру можна робити як засобами 1С, так і за допомогою SQL.

Можу сказати, що заповнення такої структури для 17-ти мільйонів значень займає десь 20-25 хвилин. Природно, користувачі в цей момент не повинні змінювати значення довідника.

Якщо ми розрахуємо для одного мільйона значень десь 100 символів по 6 у фрагменті, вийде десь 4,7 Гб. Потрібно запланувати, щоб це місце у вас було. Якщо у вас в довіднику, наприклад, 100 мільйонів значень, то ви повинні запланувати місце, яке буде доступно на диску.

Необхідність обліку статистики популярності фрагментів

Чи завжди цей метод буде працювати швидко?

На це впливає статистика популярності фрагментів.

  • Наприклад, у вас є фрагмент «Алекс», який може входити в ім'я Олексій, в батькові Олексійович, в прізвище Алексєєнко і т.д. Цей фрагмент може входити в 50-100 тисяч записів.
  • А є рідко використовуються фрагменти.

Таким чином, з'являється статистика популярності за фрагментами.

Зверніть увагу, що якщо популярність фрагментів низька (100 елементів), то ми отримуємо прискорення - 0,1 секунду.

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

Таким чином, необхідно зробити поліпшену схему виконання запиту, В якій ми спочатку б отримали значення популярності підзапиту. Це робиться трьома-п'ятьма рядками в 1С. При цьому ми точно знаємо, що якщо рядок непопулярна, то йде по першій гілці, а якщо популярна, то по другий.

Як працює прискорення? Йде запит пошуку з форми, далі ми звертаємося до регістру відомостей зі статистикою, отримуємо елемент і далі вибираємо, що використовувати - класичний або прискорений запит.

А тепер давайте розглянемо, як виконується SQL-запит на SQL-сервері.

На слайді представлена ​​спрощена схема:

  • йде запит до оптимізатора;
  • ми дивимося статистику по полях, які використовуються в запиті;
  • вибираємо, який план виконання використовувати, тобто вибираємо стратегію виконання запиту (наприклад, вкладений цикл).

На що схожа реалізована нами схема?

  • Ми зробили свій індекс. Чи не стандартний індекс SQL, що не індекс 1С, а свій індекс, який потрібен для вирішення цього завдання;
  • Більш того, зіткнулися з тим, що потрібна своя статистика;
  • І потрібен власний оптимізатор, Який за цією статистикою вирішує, яку гілку вибрати.

Виходячи з цієї логіки, можна сказати, що цей процес розкриває сенс того, для чого нам індекси, статистика і оптимізатор.

Хто не знав, для чого потрібно обслуговувати статистику в SQL, загляньте в цю логіку, і ви зрозумієте, що якщо вона неправильна або неактуальна, то ми підемо по неправильній гілці. Запит буде гальмувати. Розуміємо, для чого якісно і правильно обслуговувати статистику - це впливає на продуктивність, на індекс.

Якщо індексу немає - будемо сканувати все значення.

Таким чином, ми створили хоч примітивний, але свій оптимізатор. Можна сказати, що промацали «на пальцях» то, як це робить MS SQL та інші СУБД, причому створивши свої структури.

Прискорення «великих» документів

Перейду до другої темі - прискорення великих документів.

Ми в виробничих завданнях часто стикаємося з якимись регламентними процедурами, як: закриття місяця, звіт агенту, розрахунок собівартості. Ці важкі, масивні документи проводяться і заповнюються значну кількість часу. А коли ми заглядаємо в відладчик і робимо на цих операціях трасування, то бачимо, що 1С через підрядник вставляє значення в якусь таблицю і на це йде основний час. І нічого з цим поробити не можна. Єдина рекомендація, яку можна запропонувати - це прискорити диск (ефективність цього рішення дуже сумнівна і вимагає попереднього аналізу).

Пропоную повернутися в історію і розглянути, як це робилося в 1С, починаючи з 8.0 до 8.3 - це робилося через підрядник. SQL-сервер кожен раз аналізував запит, його обробляв, створював план виконання, додавав, відправляв команду в сторону 1С про успішність і отримував наступний запит. І такими step by step йшли запити від 1С сервера додатки до MS SQL.

Зрозуміло, що якщо у вас 40 записів в документі, то проблем виникнути не повинно. Якщо записів у вас стає 10 тисяч і більше (бувають організації, де в регламентних документах мільйон записів), то цей процес займає дуже тривалий час. Одна запис обробляється дуже швидко, але в документі їх занадто багато. На що йдуть накладні витрати? На мережу, на виконання запиту, на зворотний сигнал, на обробку цього сигналу в системі 1С - разом, сума чотирьох етапів. Всі етапи підсумовуються, множаться на мільйон рядків, і виходять наші тривалі очікування. Зрозуміло, що це не страшно.

В 1С, починаючи з 8.3, зроблені поліпшення. Тепер запит для вставки в тимчасові таблиці і в регістри відомостей готується на SQL-сервері, і його подальше виконання відбувається за допомогою класичних RPC-викликів, де сам провайдер доступу 1С (Native або OLE DB) групує записи і вставляє їх по N рядків (як правило 100 рядків).

Таким чином, досягається прискорення від 30% до 300%. Але це все одно недостатньо, тому що сьогодні у вас 10 тисяч рядків, завтра 20 тисяч рядків. Це не принципове рішення проблеми, ви все одно з нею зіткнетеся, але тільки через півроку / рік.

яка найбільш швидка вставкав SQL-сервер, та й взагалі в будь-яку СУБД?

це BULK INSERT. В 1С BULK INSERT використовується, але для інших завдань. Роботу з «великими» документами також хотілося б прискорити шляхом укрупнення вставок INSERT і додавання записів єдиним масивом в базу даних SQL-сервера.

Подивимося, який досягається ефект. У розглянутому прикладі отримано прискорення десь в 5 разів, але можна прискоритися і в 10 разів. Теоретично основна проблема для того, щоб це прискорювалося значно сильніше - це швидкість диска. Диск може є вузьким місцем.

також важливо пам'ятати про такий критерій, як індекси. Якби ми вставляли BULK INSERT в таблицю без поновлення індексів, то ми б отримали значне прискорення (результат менш ніж за секунду). Тут ми отримуємо 69 ​​секунд за рахунок того, що кожна вставка в таблицю вимагає REFRESH індексу.

У будь-якому випадку, цей спосіб дозволяє досягти ефекту в 5-10 разів.

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

Можливості оптимізації безмежні

Таким чином, можливості оптимізації безмежні. Єдине - не захоплюватися. До оптимізації завжди має сенс порахувати, чи буде передбачуваний ефект чи ні. Також я б радив в якихось ситуаціях «підніматися» над проблемою, використовувати не класичні методи оптимізації запиту, а якісь зовсім інші, які можуть принести більший результат.

****************

Дана стаття написана за підсумками доповіді (), прочитаного на конференції INFOSTART EVENT 2017 COMMUNITY.