Размер таблиц файловой базы 1С

Секционирование («партицирование») в SQL Server, при кажущейся простоте («да чего там – размазываешь таблицу и индексы по файловым группам, получаешь профит в администрировании и производительности») – достаточно обширная тема. Ниже я попробую описать как создать и применить функцию и схему секционирования и с какими проблемами можно столкнуться. О преимуществах я говорить не буду, кроме одного — переключение секций, когда вы моментально убираете из таблицы огромный набор данных, либо наоборот — моментально загружаете в таблицу не менее огромный набор.
Как гласит msdn: «Данные секционированных таблиц и индексов подразделяются на блоки, которые могут быть распределены по нескольким файловым группам в базе данных. Данные секционируются горизонтально, поэтому группы строк сопоставляются с отдельными секциями. Все секции одного индекса или таблицы должны находиться в одной и той же базе данных. Таблица или индекс рассматриваются как единая логическая сущность при выполнении над данными запросов или обновлений».
Там же перечислены основные преимущества:

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

Другими словами, секционирование применяется для горизонтального масштабирования. Таблица/индексы «размазываются» по разным файловым группам, которые могут находиться на разных физических дисках, что значительно повышает удобство администрирования и, теоретически, позволяет повысить производительность запросов к этим данным – можно либо читать только нужную секцию (меньше данных), либо читать всё параллельно (устройства разные, читается быстро). Практически же, всё несколько сложнее и повышение производительности запросов к секционированным таблицам может работать только в том случае, если в ваших запросах используется отбор по тому полю, по которому вы проводили секционирование. Если у вас ещё нет опыта работы с секционированными таблицами, просто учтите, что производительность ваших запросов может не то, чтобы не измениться, но может ухудшиться, после того как вы секционируете свою таблицу.
Поговорим о стопроцентном преимуществе, которое вы однозначно получаете вместе с секционированием (но которым тоже нужно суметь воспользоваться) – это гарантированное повышение удобства управления вашей БД. Например, у вас есть таблица с миллиардом записей, из которых 900 миллионов относятся к старым («закрытым») периодам и используются только для чтения. С помощью секционирования вы можете вынести эти старые данные в отдельную файловую группу только для чтения, забэкапить её и больше не тащить их во все свои ежедневные бэкапы – скорость создания резервной копии возрастёт, а размер уменьшится. Вы можете перестраивать индекс не по всей таблице, а по выбранным секциям. Кроме того, вырастает доступность вашей БД – если одно из устройств, содержащих файловую группу с секцией, выйдет из строя, остальные будут по-прежнему доступны.

Чтобы добиться остальных преимуществ (мгновенное переключение секций; повышение производительности) – нужно специально проектировать структуру данных и писать запросы.
Предполагаю, что уже достаточно смутил читателя и теперь уже можно переходить к практике.
Во-первых, создадим базу с 4 файловыми группами, в которой будем проводить эксперименты:
create database on primary (name =’PTestPrimary’, filename = ‘E:\data\partitionTestPrimary.mdf’, size = 8092KB, filegrowth = 1024KB) , filegroup (name =’PTestFG1′, filename = ‘E:\data\partitionTestFG1.ndf’, size = 8092KB, filegrowth = 1024KB) , filegroup (name =’PTestFG2′, filename = ‘E:\data\partitionTestFG2.ndf’, size = 8092KB, filegrowth = 1024KB) , filegroup (name =’PTestFG3′, filename = ‘E:\data\partitionTestFG3.ndf’, size = 8092KB, filegrowth = 1024KB) log on (name = ‘PTest_Log’, filename = ‘E:\data\partitionTest_log.ldf’, size = 2048KB, filegrowth = 1024KB); go alter database set recovery simple; go use partitionTest;
Создадим таблицу, которую будем мучать.
create table ptest (id int identity(1,1), dt datetime, dummy_int int, dummy_char char(6000));
И заполним её данными за один год:
;with nums as ( select 0 n union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9 ) insert into ptest(dt, dummy_int, dummy_char) select dateadd(hh, rn-1, ‘20180101’) dt, rn dummy_int, ‘dummy char column #’ + cast(rn as varchar) from ( select row_number() over(order by (select (null))) rn from nums n1, nums n2, nums n3, nums n4 )t where rn < 8761
Теперь таблица pTest содержит по одной записи за каждый час 2018-го года.
Теперь нужно создать функцию секционирования, описывающую граничные условия для разделения данных на секции. SQL Server поддерживает только секционирование по диапазонам.
Мы будем секционировать нашу таблицу по столбцу dt (datetime) таким образом, чтобы каждая секция содержала в себе данные за 4 месяца (тут я облажался — на самом деле первая секция будет содержать данные за 3, вторая за 4, третья за 5 месяцев, но для целей демонстрации — это не проблема)
create partition function pfTest (datetime) as range for values (‘20180401’, ‘20180801’)
Вроде бы всё нормально, но здесь я сознательно допустил одну «ошибку». Если посмотреть синтаксис в msdn, то вы увидите, что при создании можно указывать к какой секции будет относиться указанная граница – к левой, или к правой. По умолчанию, по какой-то неведомой причине, указанная граница относится к «левой» секции, поэтому для моего случая корректно было бы создать функцию секционирования следующим образом:
create partition function pfTest (datetime) as range right for values (‘20180401’, ‘20180801’)
В то время, как я, фактически, выполнил:
create partition function pfTest (datetime) as range left for values (‘20180401’, ‘20180801’)
Но к этому мы вернёмся позже и пересоздадим нашу функцию секционирования. Пока же продолжим с тем, что получилось, чтобы понять, что же получилось и почему это не очень хорошо для нас.

После создания функции секционирования, нужно создать схему секционирования. Она чётко привязывает секции к файловым группам:
create partition scheme psTest as partition pfTest to (, , )
Как вы видите, все три наши секции будут лежать в разных файловых группах. Теперь пришло время секционировать нашу таблицу. Для этого нам нужно создать кластерный индекс и вместо указания файловой группы, в которой он должен располагаться, указать схему секционирования:
create clustered index cix_pTest_id on pTest(id) on psTest(dt)
И здесь тоже я допустил «ошибку» в текущей схеме – я вполне мог создать уникальный кластерный индекс по этому столбцу, однако, при создании уникального индекса, столбец, по которому производится секционирование, обязательно должен входить в индекс. А я хочу показать с чем можно столкнуться при такой конфигурации.
Теперь посмотрим, что же мы получили в текущей конфигурации (запрос взят отсюда):
SELECT sc.name + N’.’ + so.name as , si.index_id as , si.type_desc as , si.name as , stat.row_count AS , stat.in_row_reserved_page_count * 8./1024./1024. as , stat.lob_reserved_page_count * 8./1024./1024. as , p.partition_number AS , pf.name as , CASE pf.boundary_value_on_right WHEN 1 then ‘Right / Lower’ ELSE ‘Left / Upper’ END as , prv.value as , fg.name as FROM sys.partition_functions AS pf JOIN sys.partition_schemes as ps on ps.function_id=pf.function_id JOIN sys.indexes as si on si.data_space_id=ps.data_space_id JOIN sys.objects as so on si.object_id = so.object_id JOIN sys.schemas as sc on so.schema_id = sc.schema_id JOIN sys.partitions as p on si.object_id=p.object_id and si.index_id=p.index_id LEFT JOIN sys.partition_range_values as prv on prv.function_id=pf.function_id and p.partition_number= CASE pf.boundary_value_on_right WHEN 1 THEN prv.boundary_id + 1 ELSE prv.boundary_id END /* For left-based functions, partition_number = boundary_id, for right-based functions we need to add 1 */ JOIN sys.dm_db_partition_stats as stat on stat.object_id=p.object_id and stat.index_id=p.index_id and stat.index_id=p.index_id and stat.partition_id=p.partition_id and stat.partition_number=p.partition_number JOIN sys.allocation_units as au on au.container_id = p.hobt_id and au.type_desc =’IN_ROW_DATA’ /* Avoiding double rows for columnstore indexes. */ /* We can pick up LOB page count from partition_stats */ JOIN sys.filegroups as fg on fg.data_space_id = au.data_space_id ORDER BY , , , ;

Таким образом, мы получили три не очень удачные секции – первая хранит данные с начала времён по 01.04.2018 00:00:00 включительно, вторая – с 01.04.2018 00:00:01 по 01.08.2018 00:00:00 включительно, третья с 01.08.2018 00:00:01 до конца света (доли секунд я сознательно упустил, потому что не помню с какой градацией SQL Server записывает эти доли, но смысл передан верно).
Теперь создадим некластерный индекс по полю dummy_int, «выровненный» по той же схеме секционирования.
А зачем нам выровненный индекс?выровненный индекс нам нужен, чтобы мы могли выполнять операцию переключения секции (switch) – а это одна из тех операций, ради которой, зачастую, и заморачиваются с секционированием. Если в таблице есть хотя бы один невыровненный индекс — вы не сможете выполнить переключение секции
create nonclustered index nix_pTest_dummyINT on pTest(dummy_int) on psTest(dt);
И посмотрим, почему я говорил, что ваши запросы могут стать медленнее, после внедрения секционирования. Выполним запрос:
SET STATISTICS TIME, IO ON; select id from pTest where dummy_int = 54 SET STATISTICS TIME, IO OFF;
И посмотрим статистику выполнения:
Table ‘ptest’. Scan count 3, logical reads 6, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
И план выполнения:

Поскольку наш индекс «выровнен» по секциям, условно, на каждой секции создан свой собственный индекс, «не связанный» с индексами на других секциях. Условий на поле, по которому секционирован индекс, мы не наложили, поэтому SQL Server вынужден выполнять Index Seek в каждой секции, фактически, 3 Index Seek вместо одного.
Давайте попробуем исключить одну секцию:
SET STATISTICS TIME, IO ON; select id from pTest where dummy_int = 54 and dt < ‘20180801’ SET STATISTICS TIME, IO OFF;
И посмотрим статистику выполнения:
Table ‘ptest’. Scan count 2, logical reads 4, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Ага, одна секция была исключена и поиск нужного значения вёлся только в двух секциях.
Это то, о чём обязательно нужно помнить, принимая решение о секционировании. Если у вас есть запросы, которые не используют ограничение по тому полю, по которому секционирована таблица, у вас может возникнуть проблема.
Некластерный индекс нам больше не нужен, поэтому я его удаляю
drop index nix_pTest_dummyINT on pTest;
А зачем был нужен некластерный индекс?он, в общем-то и не был нужен, тоже самое я мог показать и с кластерным индексом, не знаю зачем его создавал, но раз уж сделал и скриншотов понаделал — не пропадать же добру
Теперь рассмотрим следующий сценарий: данные из этой таблицы мы каждые 4 месяца архивируем – убираем старые данные и добавляем секцию для следующих четырёх месяцев (организация «скользящего окна» описана в msdn и куче блогов).
Разобьём задачу на мелкие и понятные подзадачи:

  1. Добавим секцию для данных с 01.01.2019 по 01.04.2019
  2. Создадим пустую stage-таблицу
  3. Переключим секцию с данными до 01.04.2018 в stage-таблицу
  4. Избавимся от пустой секции

Поехали:
1. Объявляем, что новая секция будет создана в файловой группе FG1, потому что она у нас скоро освободится:
alter partition scheme psTest next used ;
И меняем функцию секционирования, добавляя новую границу:
SET STATISTICS TIME, IO ON; alter partition function pfTest() split range (‘20190101’); SET STATISTICS TIME, IO OFF;
Смотрим статистику:
Table ‘ptest’. Scan count 1, logical reads 76171, physical reads 0, read-ahead reads 753, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. Table ‘Worktable’. Scan count 1, logical reads 7440, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Всего в таблице (кластерном индексе) 8809 страниц, так что количество чтений, конечно, за гранью добра и зла. Посмотрим, что у нас теперь есть по секциям.


В целом, всё как и ожидалось – появилась новая секция с верхней границей (помните, что граничные условия у нас относятся к левой секции) 01.01.2019 и пустая секция, в которой будут остальные данные, у которых дата больше.
Вроде бы всё нормально, но почему так много чтений? Посмотрим внимательно на рисунок выше, и увидим, что данные из третьей секция, которые были в FG3 оказались в FG1, а вот следующая секция, пустая, в FG3.
2. Создаём stage-таблицу.
Для переключения (switch) секции в таблицу и обратно, нам требуется пустая таблица, в которой созданы все те же ограничения и индексы, что и на нашей секционированной таблице. Таблица должна быть в той же файловой группе, что и секция, которую мы хотим туда «переключить». Первая (архивная) секция лежит в FG1, поэтому создаём таблицу и кластерный индекс там же:
create table stageTest (id int identity(1,1), dt datetime, dummy_int int, dummy_char char(6000)) ; create clustered index cix_stageTest_id on stageTest(id) on ;
Секционировать эту таблицу не нужно.
3. Теперь мы готовы к переключению:
SET STATISTICS TIME, IO ON; alter table pTest switch partition 1 to stageTest SET STATISTICS TIME, IO OFF;
И вот, что мы получаем:
Сообщение 4947, уровень 16, состояние 1, строка 59 ALTER TABLE SWITCH statement failed. There is no identical index in source table ‘PartitionTest.dbo.pTest’ for the index ‘cix_stageTest_id’ in target table ‘PartitionTest.dbo.stageTest’ .
Забавно, посмотрим, что у нас в индексах:
select o.name tblName, i.name indexName, c.name columnName, ic.is_included_column from sys.indexes i join sys.objects o on i.object_id = o.object_id join sys.index_columns ic on ic.object_id = i.object_id and ic.index_id = i.index_id join sys.columns c on ic.column_id = c.column_id and o.object_id = c.object_id where o.name in (‘pTest’, ‘stageTest’)

Помните, я писал, что нужно было делать уникальный кластерный индекс на секционированной таблице? Вот именно поэтому и нужно было. При создании уникального кластерного индекса, SQL Server потребовал бы явного включения столбца, по которому мы секционируем таблицу, в индекс, а так он добавил его сам и забыл сказать об этом. И я правда не понимаю почему так.
Но, в общем, проблема понятна, пересоздаём кластерный индекс на stage-таблице.
create clustered index cix_stageTest_id on stageTest(id, dt) with (drop_existing = on) on ;
И теперь ещё раз пробуем выполнить переключение секции:
SET STATISTICS TIME, IO ON; alter table pTest switch partition 1 to stageTest SET STATISTICS TIME, IO OFF;
Та-дам! Секция переключена, смотрим чего нам это стоило:
SQL Server parse and compile time: CPU time = 0 ms, elapsed time = 0 ms. SQL Server Execution Times: CPU time = 0 ms, elapsed time = 0 ms. SQL Server parse and compile time: CPU time = 0 ms, elapsed time = 0 ms. SQL Server Execution Times: CPU time = 0 ms, elapsed time = 0 ms. SQL Server Execution Times: CPU time = 0 ms, elapsed time = 3 ms.
А ничего. Переключение секции в пустую таблицу и наоборот (полной таблицы в пустую секцию) – это операция исключительно над метаданными и это именно то, из-за чего секционирование — это очень и очень крутая штука.
Посмотрим, что там с нашими секциями:

А с ними всё здорово. В первой секции осталось ноль записей, они благополучно уехали в таблицу stageTest. Можем двигаться дальше
4. Всё, что нам осталось – это удалить нашу пустую первую секцию. Выполним и посмотрим, что произойдёт:
SET STATISTICS TIME, IO ON; alter partition function pfTest() merge range (‘20180401’); SET STATISTICS TIME, IO OFF;
И это тоже операция только над метаданными, в нашем случае. Смотрим на секции:

У нас осталось, как и было, всего 3 секции, каждая в своей файловой группе. Миссия выполнена. Что можно было бы тут улучшить? Ну, во-первых, хотелось бы, чтобы граничные значения относились к «правым» секциям, чтобы секции содержали все данные за 4 месяца. И хотелось бы, чтобы создание новой секции обходилось меньшей кровью. Читать данных в десять раз больше, чем сама таблица – перебор.
С первым мы сделать сейчас ничего не можем, а вот со вторым – попробуем. Создадим новую секцию, которая будет содержать данные с 01.01.2019 по 01.04.2019, а не до конца времён:
alter partition scheme psTest next used ; SET STATISTICS TIME, IO ON; alter partition function pfTest() split range (‘20190401’); SET STATISTICS TIME, IO OFF;
И видим:
SQL Server parse and compile time: CPU time = 0 ms, elapsed time = 0 ms. SQL Server Execution Times: CPU time = 0 ms, elapsed time = 0 ms. SQL Server parse and compile time: CPU time = 0 ms, elapsed time = 0 ms. SQL Server Execution Times: CPU time = 0 ms, elapsed time = 0 ms.
Ха! То есть теперь это операция только над метаданными? Да, если вы «делите» пустую секцию – это операция только над метаданными, поэтому правильным решением будет держать и слева, и справа по гарантированно пустой секции и при необходимости выделения новой – «вырезать» их оттуда.
Посмотрим теперь, что произойдёт, если я захочу вернуть данные из stage-таблицы назад в секционированную таблицу. Для этого мне будет нужно:

  1. Создать новую секцию слева для данных
  2. Переключить (switch) таблицу в эту секцию

Пробуем (и помним, что stageTest в FG1):
alter partition scheme psTest next used ; SET STATISTICS TIME, IO ON; alter partition function pfTest() split range (‘20180401’); SET STATISTICS TIME, IO OFF;
Видим:
Table ‘Worktable’. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. Table ‘ptest’. Scan count 1, logical reads 2939, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Ну неплохо, т.е. прочитали только левую секцию (которую делим) и всё. Окей. Чтобы переключить несекционированную непустую таблицу в секцию секционированной таблицы, на таблице-источнике обязательно нужны ограничения, чтобы SQL Server знал, что всё будет хорошо и переключение можно сделать как операцию над метаданными (а не читать всё подряд и проверять – подходит под условия секции или нет):
alter table stageTest add constraint check_dt check (dt <= ‘20180401’)
Пробуем переключить:
SET STATISTICS TIME, IO ON; alter table stageTest switch to pTest partition 1 SET STATISTICS TIME, IO OFF;

Статистика:
SQL Server Execution Times: CPU time = 15 ms, elapsed time = 39 ms.
Опять-таки, операция только над метаданными. Смотрим, что там с нашими секциями:

Окей. Вроде разобрались. А теперь попробуем пересоздать функцию и схему секционирования (я удалил схему и функцию секционирования, пересоздал и перезаполнил таблицу и заново создал кластерный индекс по новой схеме секционирования):
create partition function pfTest (datetime) as range right for values (‘20180401’, ‘20180801’)
Посмотрим, какие секции есть у нас сейчас:

Отлично, теперь у нас три «логичных» секции – с начала времен до 01.04.2018 00:00:00 (не включительно), с 01.04.2018 00:00:00 (включительно) по 01.08.2018 00:00:00 (не включительно) и третья, всё, что больше или равно 01.08.2018 00:00:00.
Теперь попробуем выполнить ту же задачу по архивации данных, которую мы выполняли с предыдущей функцией секционирования.
1. Добавляем новую секцию:
alter partition scheme psTest next used ; SET STATISTICS TIME, IO ON; alter partition function pfTest() split range (‘20190101’); SET STATISTICS TIME, IO OFF;
Смотрим статистику:
Table ‘Worktable’. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. Table ‘ptest’. Scan count 1, logical reads 3685, physical reads 0, read-ahead reads 4, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. Table ‘Worktable’. Scan count 1, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Неплохо, по крайней мере разумно – прочитали только крайнюю секцию. Смотрим, что там у нас по секциям:
Обратите внимание, что теперь, заполненная третья секция осталась на месте, в FG3, а новая пустая секция создалась в FG1.
2. Создаём stage-таблицу и ПРАВИЛЬНЫЙ кластерный индекс по ней
create table stageTest (id int identity(1,1), dt datetime, dummy_int int, dummy_char char(6000)) ; create clustered index cix_stageTest_id on stageTest(id, dt) on ;
3. Переключаем секцию
SET STATISTICS TIME, IO ON; alter table pTest switch partition 1 to stageTest SET STATISTICS TIME, IO OFF;
Статистика говорит, что операция над метаданными:
SQL Server Execution Times: CPU time = 0 ms, elapsed time = 5 ms.
Теперь уже всё без сюрпризов.
4. Убираем ненужную секцию
SET STATISTICS TIME, IO ON; alter partition function pfTest() merge range (‘20180401’); SET STATISTICS TIME, IO OFF;
А вот тут нас ждёт сюрприз:
Table ‘ptest’. Scan count 1, logical reads 27057, physical reads 0, read-ahead reads 251, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Смотрим, что там у нас с секциями:
И вот тут становится понятно: наша секция #2 переехала из файловой группы fg2 в файловую группу fg1. Класс. Можем ли мы с этим что-то сделать?
Можем, просто нам всегда надо иметь пустую секцию и «уничтожать» границу между «вечнопустой» левой секций и той секцией, которую мы «переключили» (switch) в другую таблицу.
В качестве заключения:

  1. Используйте полный синтаксис create partition function, не полагайтесь на значения по умолчанию – вы можете получить не то, что хотели.
  2. Держите слева и справа по пустой секции – они вам очень пригодятся при организации «скользящего окна».
  3. Split и merge непустых секций – это всегда больно, по возможности избегайте этого.
  4. Проверьте свои запросы — если они не используют фильтр по тому столбцу, по которому вы планируете секционировать таблицу и вам нужна возможность переключения секций — их производительность может значительно снизиться.
  5. Если вы хотите что-то сделать, сначала протестируйте не в продакшене.

Надеюсь, материал был полезен. Возможно вышло скомкано, если считаете, что что-то из заявленного не раскрыто, пишите, постараюсь доделать. Спасибо за внимание.

Когда программу 1С впервые устанавливают на компьютер, она, как правило, работает быстро и без задержек. Но проходит время, данные накапливаются, база увеличивается в размере. Добавляются новые пользователи, компьютер со временем устаревает и перестает удовлетворять системным требованиям. Все эти факторы негативно влияют на быстродействие. В этой статье, на примере программы 1С:Бухгалтерия 3.0, рассмотрим несколько способов ускорить работу программы.

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

Настройка регламентных и фоновых заданий.

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

Откройте перечень регламентных и фоновых заданий: раздел Администрирование –> Обслуживание –> Регламентные операции –> Регламентные и фоновые задания.

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

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

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

Рассмотрим, как настроить расписание загрузки курсов валют. Нужно установить курсор на нужную строку и сделать двойной щелчок мышкой. Галка включено должна быть установлена. Нажать на ссылку Расписание. В открывшемся окне перейти на нужную закладку, например, дневное, установить время начала (на скриншоте 12:00) и нажать Ок. При такой настройке курсы будут загружаться каждый день с 12:00.

На закладке Фоновые задания можно отменить уже выполняющееся фоновое задание нажав по соответствующей кнопке. Если появится сообщение, как на скриншоте, просто нажать ОК.

Тестирование и исправление информационной базы

Войдите в конфигуратор. Откройте меню Администрирование –> тестирование и исправление. Установите необходимые флажки (можно установить все) и нажмите выполнить.

Некоторые варианты проверки будут понятны только техническим специалистам, но тем не менее рассмотрим их подробнее:

  • Реиндексация таблиц информационной базы – перестраивает индексы таблиц и повышает быстродействие работы программы;
  • Проверка логической целостности информационной базы –включает в себя ряд стандартных проверок целостности прикладных объектов, например, проверка того, что все объекты метаданных в пределах одной ветки имеют уникальные имена;
  • Проверка ссылочной целостности информационной базы – проверка целостности базы данных для обнаружения «битых» ссылок. Например, если какой-либо объект конфигурации ссылается на несуществующий объект. Если выбираем такой вариант, то дополнительно становятся доступны настройки:
    • При наличии ссылок на несуществующие объекты означает, что при обнаружении «битых» ссылок, алгоритм будет обрабатывать такие ссылки в соответствии с выбранным вариантом;
    • При частичной потере данных объектов означает, что остаток данных достаточен для восстановления данных какого-либо объекта.
  • Пересчет итогов – перерасчет итогов таблиц регистров накопления и регистров бухгалтерии. Этот вариант проверки так же может увеличить быстродействие программы;
  • Сжатие таблиц информационной базы – уменьшает размер базы данных. Сжатие происходит за счет удаления лишних данных внутри конфигурации. Ваши введенные данные не пострадают;
  • Реструктуризация таблиц информационной базы – оптимизирует структуру базы данных с целью повышения быстродействия.

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

Индексация полнотекстового поиска (либо отключение)

Про назначение полнотекстового поиска ранее я уже снял видеоурок, рекомендую его посмотреть.

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

Если же хотите его использовать, тогда обновите индекс. Для этого нажмите на ссылку Настроить. В открывшимся окне нажмите на кнопку Обновить индекс.

Обновление платформы и конфигурации

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

  • 1С:Предприятие 8.3 (…) – версия платформы;
  • Бухгалтерия предприятия, редакция 3.0 (…) – версия релиза.

Проверить наличие обновлений и самостоятельно обновить программу можно из меню Администрирование –> интернет поддержка и сервисы –> обновление версии программы. При затруднениях рекомендуется обратиться в обслуживающую организацию.

Запуск в Тонком клиенте

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

Тестирование физической целостности утилитой chdbfl

Нужно зайти в папку с установленной платформой в конечную папку bin. Запустить файл chdbfl, прописать путь к базе, поставить галку исправлять обнаруженные ошибки и нажать выполнить.

После окончания тестирования окно закрыть и проверить базу на работоспособность.

Отключение ненужной функциональности

Меню Администрирование –> Функциональность. Внимательно проверить все закладки и отключить неиспользуемые функции.

Например, если в организации нет экспорта или производства, эти настройки можно отключить. (включить можно в любой момент).

Свертка информационной базы

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

Данные рекомендации вполне можно сделать самостоятельно. В статье описано именно действия с программой. Помимо них для ускорения работы 1С можно настроить используемую антивирусную программу, проверить параметры компьютера и при необходимости увеличить его характеристики или заменить на новый, установить твердотельный жесткий диск SSD.

Секционирование представлений

В СУБД Oracle есть возможность секционировать представления. Основная идея секционирования представлений проста. Пусть физическая таблица разбита на несколько таблиц (необязательно с помощью методов секционирования таблиц) в соответствии с критерием разбиения, который делает обработку запроса более производительной. Критерий разбиения будем называть предикатом секционирования. Тогда можно создать и настроить представления таким образом, чтобы с их помощью обращение к данным этих таблиц было проще для пользователя. Секция представления определяется в соответствии с диапазоном значений ключа секционирования. Запросы, которые используют диапазон значений для выборки данных из секций представления, будут получать доступ только к тем секциям, которые соответствуют диапазонам значений ключа секционирования.

Секции представления могут быть определены предикатами секционирования, заданными либо при помощи ограничения CHECK, либо с использованием предложения WHERE. Покажем, как могут быть применены оба приема, на примере несколько модифицированной таблицы «Продажи» (Sales), которую мы рассматривали в предыдущем разделе. Допустим, что данные о продажах для календарного года размещаются в четырех отдельных таблицах, каждая из которых соответствует кварталу года — Q1_Sales, Q2_Sales, Q3_Sales и Q4_Sales.

Пример 20.14.

Секционирование представлений с помощью ограничения CHECK. С помощью команды ALTER TABLE можно добавить ограничения на колонку «Дата продажи» (s_date) каждой таблицы, чтобы ее строки соответствовали одному из кварталов года. Созданное затем представление sales дает возможность обращаться к этим таблицам, как к одной, так и ко всем вместе.

ALTER TABLE Q1_Sales ADD CONSTRAINT C0 CHECK (s_date BETWEEN ‘jan-1-2002’ AND ‘mar-31-2002’); ALTER TABLE Q2_Sales ADD CONSTRAINT C1 CHECK (s_date BETWEEN ‘apr 1-2002’ AND ‘jun-30-2002’); ALTER TABLE Q3_Sales ADD CONSTRAINT C2 check (s_date BETWEEN ‘jul-1-2002’ AND ‘sep-30-2002’); ALTER TABLE Q4_Sales ADD CONSTRAINT C3 check (s_date BETWEEN ‘oct-1-2002’ AND ‘dec-31-2002’); CREATE VIEW sales_v AS SELECT * FROM Q1_Sales UNION ALL SELECT * FROM Q2_Sales UNION ALL SELECT * FROM Q3_Sales UNION ALL SELECT * FROM Q4_Sales;

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

Пример 20.15.

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

CREATE VIEW sales_v AS SELECT * FROM Q1_Sales WHERE s_date BETWEEN ‘jan-1-2002’ AND ‘mar-31-2002’ UNION ALL SELECT * FROM Q2_Sales WHERE s_date BETWEEN ‘apr-1-2002’ AND ‘jun-30-2002’ UNION ALL SELECT * FROM Q3_Sales WHERE s_date BETWEEN ‘jul-1-2002’ AND ‘sep-30-2002’ UNION ALL SELECT * FROM Q4_Sales WHERE s_date BETWEEN ‘oct-1-2002’ AND ‘dec-31-2002’;

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

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

SELECT * FROM east_sales@icp.ac.ru WHERE LOC = ‘EAST’ UNION ALL SELECT * FROM west_sales@ioc.ac.ru WHERE LOC = ‘WEST’;

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

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

Секционирование таблиц в СУБД семейства MS SQL Server

Создание секционированных таблиц

В СУБД семейства MS SQL Server также поддерживается секционирование таблиц, индексов и представлений. Однако, в отличие от СУБД семейства Oracle, секционирование в СУБД семейства MS SQL Server выполняется по унифицированной схеме.

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

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

Для создания секционированной таблицы в СУБД MS SQL Server используются следующие объекты БД: функции секционирования и схемы секционирования. Эти объекты позволяют разделять данные на конкретные сегменты и управлять их местоположением в БД или ХД. Например, можно распределить данные по нескольким дисковым массивам в зависимости от даты поступления данных или других отличительных признаков. Следует отметить, что таблицу можно секционировать по одному из ее столбцов, и каждая секция должна содержать данные, которые не могут храниться в других секциях.

Функции секционирования

При секционировании таблицы сначала нужно определить правило, по которому данные будут разделяться на сегменты. Для сопоставления отдельных строк данных с разными сегментами служит функция секционирования.

Строки данных могут сегментироваться по колонке любого типа, кроме следующих: text, ntext, image, xml, timestamp, varchar(max), nvarchar(max), varbinary(max), псевдонимы типов данных и пользовательские типы данных среды CLR. Однако функция секционирования должна распределять каждую строку данных только в одну секцию таблицы ; иными словами, в результате применения функции одна и та же строка не может принадлежать нескольким секциям одновременно.

Чтобы секционировать таблицу, в ней необходимо создать или выбрать колонку секционирования ( ключ секционирования ). Ключ секционирования можно создать в схеме таблицы в момент создания таблицы либо добавить позднее путем модификации таблицы. Столбец может принимать значения NULL, но все строки, содержащие значения NULL, будут по умолчанию помещаться в самую левую секцию таблицы. Этого можно избежать, указав при создании функции секционирования, что значения NULL должны помещаться в самую правую секцию таблицы. Выбор левой или правой секций – важное решение проектирования, проявляющееся при изменении схемы секционирования, добавлении дополнительных секций или удалении существующих.

При создании функции секционирования можно выбрать функции LEFT или RIGHT. Разница между секциями LEFT и RIGHT состоит в размещении данных по секциям. Функция LEFT распределяет данные по принципу от самого низкого значения до самой высокой величины (то есть по возрастанию). Функция RIGHT распределяет данные по принципу от самого высокого значения до самого низкого (то есть по убыванию). Рассмотрим пример.

Пример 20.16.

Возьмем следующие примеры определения функций секционирования с использованием LEFT и RIGHT:

CREATE PARTITION FUNCTION Left_Partition (int) AS RANGE LEFT FOR VALUES (1,10,100) CREATE PARTITION FUNCTION Right_Partition (int) AS RANGE RIGHT FOR VALUES (1,10,100)

В первой функции ( Left_Partition ) значения 1, 10 и 100 размещаются соответственно в первой, второй и третьей секциях. Во второй функции ( Right_Partition ) эти значения размещаются во второй, третьей и четвертой секциях.

При создании секционированной таблицы важно, чтобы секции получились сбалансированными по кардинальности. Это позволяет оценить, сколько дискового пространства потребуется для каждой секции. Использование параметров LEFT и RIGHT определяет, куда будут размещаться данные, что, в свою очередь, задает размер секции и размеры индексов, созданных на ней.

Определить номер секции, в которую попадут те или иные данные, можно с помощью функции $PARTITION, как показано ниже:

SELECT $PARTITION.Left_Partition (10) SELECT $PARTITION.Right_Partition (10)

Первая команда SELECT возвращает значение 2, вторая – значение 3.

Схемы секционирования

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

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

Пример 20.17.

Выполним присвоение файловых групп схеме секционирования. Сначала приведем пример размещения всех секций таблицы в одной файловой группе с именем PRIMARY.

CREATE PARTITION SCHEME Primary_Left_Scheme AS PARTITION Left_Partition ALL TO ()

Чтобы разместить все секции в различных файловых группах, нужно выполнить следующую команду:

CREATE PARTITION SCHEME Different_Left_Scheme AS PARTITION Left_Partition TO (Filegroup1, Filegroup2, Filegroup3, Filegroup4)

Чтобы разместить несколько секций в различных файловых группах, нужно выполнить следующую команду:

CREATE PARTITION SCHEME Multiple_Left_Scheme AS PARTITION Left_Partition TO (Filegroup1, Filegroup2, Filegroup1, Filegroup2)

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

Пример 20.18.


увеличить изображение
Рис. 20.6. Таблица фактов «Продажи» (SALES) в схеме типа «звезда»

Сначала мы должны создать функцию секционирования:

CREATE PARTITION FUNCTION MyPartitionFunctionLeft (date) AS RANGE LEFT FOR VALUES (‘1/01/2005’, ‘1/01/2007’, ‘1/01/2009)

MyPartitionFunctionLeft — это название функции разделения, datetime — тип данных ключа секционирования, а RANGE LEFT указывает, как делить значения данных, которые связаны с датами FOR VALUES.

Ключ секционирования имеет тип данных date, т.е. это колонка «Дата события» (Date_of_Event). В команде, приведенной выше, деление строк на непересекающиеся группы построено по принципу разбиения их на двухлетние группы. Разделение на секции RANGE LEFT делит данные в диапазонах значений, показанных на рис. 20.7.


увеличить изображение
Рис. 20.7. Разделение на секции таблицы фактов «Продажи» (SALES) с использованием RANGE LEFT

Каждая область значений в секции имеет границы, которые определены в операторе FOR VALUES. Если дата продажи была 23 июня 2006 года, то строка будет храниться в секции 2 (P2).

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

CREATE PARTITION SCHEME MyPartitionScheme AS MyPartitionFunction TO (MyFilegroup1, MyFilegroup2, MyFilegroup3, MyFilegroup4)

MyPartitionScheme – это имя схемы секционирования, а имя MyPartitionFunction определяет функцию секционирования. Эта команда отображает данные в секции, которые связаны с одной или несколькими файловыми группами. Строки с данными со значениями колонки «Дата продажи» (Date_of_Event date) до 1/01/05 связаны с MyFilegroup1. Строки этой колонки со значениями, большими или равными 1/01/05 и до 1/01/07, назначены MyFilegroup2. Строки со значениями, большими или равными 1/01/07 и до момента 1/01/09, связаны с MyFilegroup3. Все остальные строки со значениями, большими или равными 1/01/09, связаны с MyFilegroup4.

Для каждого набора граничных значений (которые задаются условием FOR VALUES функции секционирования ) количество секций будет равно «Количество граничных значений» + 1 секция. Предыдущее предложение CREATE PARTITION SCHEME включает три ограничения и четыре секции. Независимо от того, созданы ли секции с RANGE RIGHT или RANGE LEFT, количество секций всегда будет равно «Количество граничных значений» + 1, вплоть до 1000 секций на таблицу.

Теперь мы можем создать секционированную таблицу фактов «Продажи» (SALES). Создание секционированной таблицы мало чем отличается от создания обычной таблицы, нужно только сослаться на имя схемы секционирования в условии ON, как показано в команде ниже.

CREATE TABLE SALES (Sales_ШВ bigint identity (1, 1) primary not clustered NOT NULL, Cust_ID bigint null, Prod_ID bigint null, Store_ID bigint null, REG_ID char(10) null, Time_of_Event time null, Quantity integer not null, Amount dec(8,2) not null, Date_of_Event date NOT NULL) ON MyPartitionScheme (Date_of_Event)

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

Можно объединять только две смежные секции. Чтобы слить две секции, выполните команду:

ALTER PARTITION FUNCTION MyPartitionFunction() MERGE RANGE (‘1/01/2007’)

Здесь секция 1 (P1) объединится с секцией P2. Это означает, что секция P2 будет содержать все строки со значением колонки «Дата продажи» (Date_of_Event) до значения даты 1/01/07. В системной таблице sys.partitions секции будут перенумерованы, начиная с единицы (не с нуля). Секции P1 и P2 станут P1, секция P3 станет P2 и P4 станет P3.

Секционирование индексов в СУБД семейства MS SQL Server

В СУБД семейства MS SQL Server предусмотрена возможность создавать секционированные индексы. Это позволяет проектировщику проектировать структуру индекса на основе разделенных данных, а не на основе всех данных таблицы. Создание секционированных индексов влечет за собой создание отдельных сбалансированных деревьев на секционированных индексах. В результате разделения индексов создаются индексы меньшего размера, и администратору БД или ХД становится проще их обслуживать во время изменения, добавления и удаления данных.

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

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

Пример. 20.19.

Создадим секционированный некластеризованный индекс на секционированной таблице «Продажи» (SALES) из предыдущего примера 20.18. Некластеризованный индекс выравнивается с таблицей; в качестве ключа некластеризованного индекса используется ключ секционирования таблицы.

CREATE NONCLUSTERED INDEX cl_multiple_partition ON SALES (Date_of_Event)

Для того чтобы создать невыровненный некластеризованный индекс на секционированной таблице «Продажи» (SALES) из примера 20.18, можно поступить следующим образом. Сначала создадим функцию секционирования для индекса.

CREATE PARTITION FUNCTION Index_Left_Partition (bigint) AS RANGE LEFT FOR VALUES (10, 50, 100)

Затем разместим все секции индекса в одной файловой группе с именем PRIMARY, выполним команду

CREATE PARTITION SCHEME Index_primary_Left_Scheme AS PARTITION Index_Left_Partition ALL TO ()

Теперь выполним команду создания индекса, как показано ниже.

CREATE NONCLUSTERED INDEX cl_multiple_partition ON multiple_partition( Cust_ID) ON Index_primary_Left_Scheme (Cust_ID)

В этом некластеризованном индексе в качестве ключа индекса используется колонка «Идентификатор покупателя» (Cust_ID), которая не является ключом секционирования таблицы «Продажи» (SALES).

Решения о секционировании индексов принимаются проектировщиком ХД на стадии проектирования или администратором ХД на стадии эксплуатации ХД. Целью секционирования индексов является либо обеспечение производительности запросов, либо упрощение процедур сопровождения индекса.

Add a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *