Форум программистов, компьютерный форум, киберфорум
Microsoft SQL Server
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
932 / 365 / 43
Регистрация: 10.05.2021
Сообщений: 1,564
Записей в блоге: 10

Секционирование. Для чего и как?

06.06.2024, 12:46. Показов 1565. Ответов 13

Студворк — интернет-сервис помощи студентам
Приветствую!

Объясните, пожалуйста, популярно (желательно — на примерах) — что такое секционирование, для чего оно нужно и как правильно организовывается?

Я так понимаю, это метод разделения данных на группы/секции/разделы/части — чтобы можно было быстрее получать данные из такой конкретной группы.
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
06.06.2024, 12:46
Ответы с готовыми решениями:

Postgresql. Секционирование таблицы по хэшу. Как происходит?
В официальной документации говорится про секционирование по хэшу. Но подробности не приводятся. Как оно происходит? Допустим, у меня...

СЕКЦИОНИРОВАНИЕ
Есть задача, таблицу я создам и все свяжу, но нужно создать секционирование: Построить информационно-логическую модель базы данных,...

Секционирование
Здравствуйте! Сначала создается структура таблицы (без указания partition by range ("column1")) и добавляются строки. Далее...

13
1305 / 359 / 97
Регистрация: 14.10.2022
Сообщений: 1,090
07.06.2024, 11:30
Лучший ответ Сообщение было отмечено Jack Famous как решение

Решение

Эээ...
Ну, секционирование в MSSQLSERVER присутствует в двух вариантах. Олдскульном, когда таблица, которую нужно разделить на части горизонтально - разделяется на несколько одинаковых по формату таблиц, с некоторыми дополнениями в констрейнтах, которые выносятся в разные таблицы, которые могут располагаться вплоть до того, что в разных БД, и даже на разных серверах, а исходная таблица заменяется на view:
https://learn.microsoft.com/ru... oned-views
Причем это доступно во всех версиях MS SQL, как бы не начиная с 4.0, т.е. "всегда было" (не поручусь, но ЕМНИП).
И т.к. при этом речь идет о различных таблицах - можно делать всё, что можно делать с таблицами. И лишь на уровне вью всё это эмулирует настоящую таблицу, впрочем, не слишком убедительно.
На мой взгляд это как раз и есть "подлинное" секционирование, без разных там фиговых листков.

И есть "настоящее" секционирование, когда таблицу можно, горизонтально же, порезать на куски, и эти куски расположить на отдельных файловых группах. При этом внешне таблица выглядит целенькой, но с ее кусками можно делать всякие интересные штуки.
Например - горячие данные, за последний месяц - разместить на быстром носителе, а исторические - на емком, но медленном. Или сжать исторические данные в колумнстор-архив, если структура таблицы позволяет. Они в 12 раз меньше места занимать будут.
По-моему, можно какие-то секции расположить на read-only файловых группах, и получить защиту изменений нативным образом (не пробовал, так что может и вру, но вроде что-то читал).
Самое прикольное, что можно делать - это грузить данные, балком, например, в отдельностоящую табличку, а потом этой самой табличкой подменить какую либо секцию в исходной табличке.
Удобно для организации хранилищ, в которых с оной стороны, нужно грузить [десяток-сотню] миллионов записей, но чтобы вставка в таблицу производилась мгновенно, в течение 0,1 сек.
У нас так несколько "живых витрин" реализовано.
Нет, сама выгрузка/загрузка длится, возможно часы. Но данные оказываются в продуктовых таблицах мгновенно, и пользователь, до последнего момента, работает с "данные продакшн на 2024-06-04 20:25:04, загруженные 2024-06-05 00:00:01", а потом, сразу "данные продакшн на 2024-06-05 03:25:04, загруженные 2024-06-05 06:00:01", без перерывов и блокировок (эдакий супер-снепшот).
Куча ограничений и дорого, конечно, но позволяет, т.с.

Ну т.д.
В основном секционирование применяют, чтобы ускорить выборку данных. Это действительно возможно, если в запросе на секционированой таблице явным образом указан ключ секционирования в предикате равенства, и запрос скомпилирован таким образом, что это не интерпретируется энжином как переменная, ну т.е. что-то типа:
T-SQL
1
2
3
Declare @i int = 10
Select * from s_Table Where i = @i
Option (recompile)
Где i - это колонка ключа секционирования.
В этом случае энжин исключит незадействованные секции и будет искать только в секции, которой принадлежит значение этого ключа. И запрос станет работать быстрее.
Ну или значение ключа секционирования указано явно, литералом. (Есть еще варианты, при которых срабатывает партишн элиминейшн, но там углуПляться надо).
Потом, если партиции лежат на файловых группах, расположенных на физически разных стораджах - чтение ускоряется, т.к. происходит в несколько потоков, по разным каналам.

Во всех остальных случаях - работа с партиционированной таблицей - МЕДЛЕННЕЕ, чем с обычной.

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

Добавлено через 3 минуты
Цитата Сообщение от uaggster Посмотреть сообщение
без перерывов и блокировок (эдакий супер-снепшот).
:-))). Разумеется, когда секция подменяется, энжин дропнет все запросы к этой таблице.
Такова селяви.
1
932 / 365 / 43
Регистрация: 10.05.2021
Сообщений: 1,564
Записей в блоге: 10
07.06.2024, 11:45  [ТС]
uaggster, большое спасибо! Суперподробно и понятно!
Цитата Сообщение от uaggster Посмотреть сообщение
Где i - это колонка ключа секционирования.
а чем это отличается от просто поля в таблице с такими же ключами "группировки"? Только то, что секции можно физически разделять по своему усмотрению?
0
1305 / 359 / 97
Регистрация: 14.10.2022
Сообщений: 1,090
07.06.2024, 11:48
Эээ... не понятен вопрос.
Начни с научпопа: https://habr.com/ru/articles/464665/
1
932 / 365 / 43
Регистрация: 10.05.2021
Сообщений: 1,564
Записей в блоге: 10
07.06.2024, 11:53  [ТС]
uaggster, хорошо) ещё раз спасибо. Вернусь, как разберу(не сегодня).
0
932 / 365 / 43
Регистрация: 10.05.2021
Сообщений: 1,564
Записей в блоге: 10
25.06.2025, 11:31  [ТС]
Приветствую!
Я вернулся

Вводные:
• таблица на примерно ярд строк и 50 полей
• высоконагруженная, постоянно активная, отключать/блокировать можно только на незначительное время (секунды)
• всегда ночью и иногда днём происходит обновление огромных блоков данных по заданному полю (числовой ключ поставщика)

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

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

Прошу поделиться своим практическим опытом по этому вопросу.
Возможно, лучший вариант мной вообще тут не рассмотрен.
0
1305 / 359 / 97
Регистрация: 14.10.2022
Сообщений: 1,090
25.06.2025, 15:46
Цитата Сообщение от Jack Famous Посмотреть сообщение
высоконагруженная, постоянно активная
А под этим что понимается?
Обычно, под "высоконагруженная" понимается вариант нагрузки, когда добавляются, изменяются и удаляются записи с высокой частотой в куче коннектов.
Когда, например, данные только читаются, пусть даже и с высокой частотой или большими порциями, или, например, только вставляются - это НЕ высоконагруженная, даже если речь идет о значительных объемах передаваемой информации.
(просто потому, что 2-3 вариант нагрузки парируется с помощью кэширования, и "это другое").
У вас точно "высоконагруженная"? Больше 20 тысяч транзакций в секунду?
0
932 / 365 / 43
Регистрация: 10.05.2021
Сообщений: 1,564
Записей в блоге: 10
25.06.2025, 16:20  [ТС]
Цитата Сообщение от uaggster Посмотреть сообщение
А под этим что понимается?
Обычно, под "высоконагруженная" понимается вариант нагрузки, когда добавляются, изменяются и удаляются записи с высокой частотой в куче коннектов.
тогда я не прав. Имел в виду высокую частоту Select'ов. До сотни/тысячи запросов в секунду, очень сомневаюсь, что больше.
0
1305 / 359 / 97
Регистрация: 14.10.2022
Сообщений: 1,090
25.06.2025, 16:42
А если просто и без изысков обновлять/заливать и всё такое - какие проблемы наблюдаются?
Просто, начинать выкрутасничать имеет смысл, когда без выкрутасов уже не получается!
Например: Вот нужно вам, например, миллион записей обновить. Вы обновляете их в лоб. Висит длинная транзакция, и система блокируется на 5 минут. Если это приемлемо - то не является проблемой и решать это не нужно.
Предположим, это проблема.
Ну, давайте запакетируем обновление, и будем обновлять циклом/курсором пакетами в 10000 записей.
Оборотная сторона медали - нужно городить курсор, и фиксировать обновление частями.
Неприемлемо, потому что, например нужно откатить всё сразу в случае ошибки?
Ну, давайте еще что-нибудь придумаем.
Но, на каждом этапе мы должны понимать, что платить придется дороже.
Итак? С чем боремся? Какую проблему решаем, и проблема ли она?
0
932 / 365 / 43
Регистрация: 10.05.2021
Сообщений: 1,564
Записей в блоге: 10
25.06.2025, 16:55  [ТС]
uaggster, уважаю структурный подход — продуктивно)

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

2. Таблица с проблемой не моя и не мне там делать. Я бы поменял многое и, скорее всего, физически разделил таблицу и создал новый арсенал инструментов для работы с пакетом новых таблиц.

3. Заполнение/обновление/удаление уже идёт пакетами по 100 тыс строк. Каждая операция обёрнута в явную транзакцию (предполагаю, что это может ускорить процесс и сократить лог). Откатить всё, в таком случае, тоже не является проблемой — можно запомнить определённые маркеры и откатиться по ним.

Собственно, вопрос в том, может ли помочь секционирование для вставки и как?
Собрать данные в буферную таблицу, одинаковую с целевой и вставлять/переключать частями посекционно, очищая целевую секцию перед этим?
0
1305 / 359 / 97
Регистрация: 14.10.2022
Сообщений: 1,090
26.06.2025, 08:48
Цитата Сообщение от Jack Famous Посмотреть сообщение
Собрать данные в буферную таблицу, одинаковую с целевой и вставлять/переключать частями посекционно, очищая целевую секцию перед этим?
Да, именно так.
1. Создаете таблицу, тождественную по структуре целевой, на той файлгруппе, где размещена загружаемая секция.
На таблице также необходимо создать констрейнт, который соответствует ограничению ключа секции.
2. Заливаете в эту таблицу данные.
3. Заливаете в эту таблицу данные из целевой секции, которые нужно сохранить при заливке.
Ну, т.е., например, у вас в секции хранится информация о 100 тыс., например, счетов. Вы заливаете еще 10 тыс, которые частично должны заместить хранящиеся.
Вот, заливаете все 10 тыс., а потом ДОливаете из целевой секции те записи, которые потом "должны остаться на месте", соответственно, не трогая тех, которые уже загрузили в новую таблицу.
4. Создаете и строите индексы на новой табличке, эквивалентные индексам целевой таблицы. Обратите внимание, что индексы должны быть выровненные.
5. Очищаете (truncate) секцию в целевой таблице.
6. Переключаете таблицу в секцию.

Кстати, если вам, по какой-то причине нужна предыдущая версия данных, то можно не транкейтить, а переключить старую секцию в другую пустую таблицу.
1
932 / 365 / 43
Регистрация: 10.05.2021
Сообщений: 1,564
Записей в блоге: 10
26.06.2025, 09:38  [ТС]
uaggster, сообщение не дописано) спасибо большое!
А есть ли у вас проверенный скриптик для создания полной копии таблицы — со всеми индексами, ограничениями и прочим?
Поделитесь, если есть возможность, пожалуйста)
0
1305 / 359 / 97
Регистрация: 14.10.2022
Сообщений: 1,090
27.06.2025, 09:29
Это кусок неадаптированного текста (просто вырвал кусок из процедуры)
Создает копии таблиц из схемы dbo, чьи имена перечислены в таблице [load].[tables_to_load]
Ключом секционирования является код филиала, и, соответственно, секция таблицы размещается на файловой группе [FКодФилиала].
Создаются 2 таблицы: Имя_таблицы_in - в нее грузятся данные перед подменой, out - туда вышибаются существующие данные (у нас в процессе загрузки вычисляется дельта (агрегаты) и складируется в лог, поэтому какое то время нужны и подменяемые и подменяющие данные). Но можно не так, out не создавать, можно просто транкейт секции в целевой таблице.

Кликните здесь для просмотра всего текста


T-SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
Set nocount, xact_abort on;
 
DECLARE @sql NVARCHAR(max) = N'',  @filial_id smallint
 
-- Создаем новые таблицы импорта
SET @sql = (
        SELECT N'Create table [tmp].' + Quotename(t2.NAME) 
        + N'(' 
        + Stuff((
                    SELECT N',' + Quotename(b.[name]) + N' ' + t.[name] 
                        + CASE 
                            WHEN t.[name] IN (N'numeric', N'decimal')
                                THEN CONCAT (N'(', b.[precision], N',', b.[scale], N')')
                            WHEN t.[name] IN (N'datetime2')
                                THEN CONCAT(N'(', b.[scale], N')')
                            WHEN t.[name] IN (N'varchar', 'char')
                                THEN CONCAT (N'(', iif(b.max_length = - 1, N'max', cast(b.max_length AS NVARCHAR(10))), N')') + IsNull(N' collate ' + b.collation_name, N'')
                            WHEN t.[name] IN (N'nvarchar', N'nchar')
                                THEN CONCAT (N'(', iif(b.max_length = - 1, N'max', cast(b.max_length / 2 AS NVARCHAR(10))), N')') + IsNull(N' collate ' + b.collation_name, N'')
                            WHEN t.[name] IN (N'varbinary', N'binary')
                                THEN CONCAT (N'(', iif(b.max_length = - 1, N'max', cast(b.max_length AS NVARCHAR(10))), N')')
                            ELSE N''
                        END 
                        + N' ' + iif(b.is_sparse = 0, N'', N'SPARSE') + N' ' + iif(b.is_nullable = 0, N'NOT NULL', N'NULL')
                    FROM sys.tables a
                    INNER JOIN sys.columns b ON a.[object_id] = b.[object_id]
                    INNER JOIN sys.types t ON b.system_type_id = t.system_type_id and b.user_type_id = t.user_type_id
                        AND b.user_type_id = t.user_type_id
                    WHERE a.object_id = aa.object_id
                    ORDER BY b.column_id ASC
                    FOR XML path(N'')
                        ,type
                    ).value(N'.', N'NVARCHAR(MAX)'), 1, 1, '') 
                    + N') ON [f' + Right(N'0000' + Cast(@filial_id AS NVARCHAR(4)), 4) + '];'
        FROM 
        sys.tables aa (nolock)
        inner join [load].[tables_to_load] t on aa.[name] = t.[name] and aa.schema_id = schema_id('dbo')
        Cross apply 
            (
            VALUES (aa.[name] + '_' + Right(N'0000' + Cast(@filial_id AS NVARCHAR(4)), 4) + N'_in')
                  ,(aa.[name] + '_' + Right(N'0000' + Cast(@filial_id AS NVARCHAR(4)), 4) + N'_out')
            ) t2(NAME)
        FOR XML path(N''), Type
        ).value(N'.', N'NVARCHAR(MAX)');
 
Exec (@sql);
 
-- Создать КЛАСТЕРНЫЕ индексы в таблицах для переключения
 
SET @sql = (
        SELECT CASE si.index_id
                WHEN 0
                    THEN N'/* No create statement (Heap) */'
                ELSE CASE si.is_primary_key
                        WHEN 1
                            THEN N'ALTER TABLE ' + QUOTENAME(N'tmp') + N'.' + QUOTENAME(t2.NAME) + N' ADD CONSTRAINT ' + QUOTENAME(N'PK_' + t2.NAME) + N' PRIMARY KEY ' + iif(si.index_id > 1, N'NON CLUSTERED ', N'CLUSTERED ')
                        ELSE N'CREATE ' + CASE 
                                WHEN si.[type] = 5 THEN N'CLUSTERED COLUMNSTORE '
                                WHEN si.[type] = 6 THEN N'NONCLUSTERED COLUMNSTORE '
                                ELSE iif(si.is_unique = 1, N'UNIQUE ', N'') + iif(si.index_id > 1, N'NONCLUSTERED ', N'CLUSTERED ')
                                END 
                        + N'INDEX ' + QUOTENAME(si.NAME) + N' ON ' + QUOTENAME(N'tmp') + N'.' + QUOTENAME(t2.NAME) + N' '
                        END
                    /* key def */
                    + isNull(N'(' + keys.key_definition + N')', '')
                    /* includes */
                    + CASE 
                        WHEN includes.include_definition IS NOT NULL AND si.[type] = 6 THEN N' (' + includes.include_definition + N') '
                        WHEN includes.include_definition IS NOT NULL AND not (si.[type] in (5,6)) THEN N' INCLUDE (' + include_definition + N')'
                        ELSE N''
                        END
                    /* filters */
                    + CASE 
                        WHEN si.filter_definition IS NOT NULL
                            THEN N' WHERE ' + si.filter_definition
                        ELSE N''
                        END
                    /* With */
                    + CASE 
                        WHEN is_primary_key <> 1 AND not(si.[type] in (5, 6))
                            THEN N' WITH(FILLFACTOR=100, STATISTICS_NORECOMPUTE=ON, ONLINE=OFF) '
                        ELSE N''
                        END
                    /* ON where? */
                    + N' ON ' + N'[f' + Right(N'0000' + Cast(@filial_id AS NVARCHAR(4)), 4) + N']' + N';'
                END AS index_create_statement
        FROM sys.indexes AS si
        INNER JOIN sys.tables AS t ON si.object_id = t.object_id
        INNER JOIN sys.schemas AS sc ON t.schema_id = sc.schema_id
        LEFT JOIN sys.filegroups AS fg ON si.data_space_id = fg.data_space_id
        /* Key list */
        OUTER APPLY (
            SELECT STUFF((
                        SELECT N', ' + QUOTENAME(c.NAME) + CASE ic.is_descending_key
                                WHEN 1
                                    THEN N' DESC'
                                ELSE N''
                                END
                        FROM sys.index_columns AS ic
                        JOIN sys.columns AS c ON ic.column_id = c.column_id
                            AND ic.object_id = c.object_id
                        WHERE ic.object_id = si.object_id
                            AND ic.index_id = si.index_id
                            AND ic.key_ordinal > 0
                        ORDER BY ic.key_ordinal
                        FOR XML PATH(N'')
                            ,TYPE
                        ).value(N'.', N'NVARCHAR(MAX)'), 1, 2, N'')
            ) AS keys(key_definition)
        /* Include list */ 
        OUTER APPLY (
            SELECT STUFF((
                        SELECT N', ' + QUOTENAME(c.NAME)
                        FROM sys.index_columns AS ic
                        JOIN sys.columns AS c ON ic.column_id = c.column_id
                            AND ic.object_id = c.object_id
                        WHERE ic.object_id = si.object_id
                            AND ic.index_id = si.index_id
                            AND ic.is_included_column = 1
                        ORDER BY c.NAME
                        FOR XML PATH('')
                            ,TYPE
                        ).value(N'.', N'NVARCHAR(MAX)'), 1, 2, N'')
            ) AS includes(include_definition)
        Cross apply 
            (
            VALUES (t.[name] + '_' + Right(N'0000' + Cast(@filial_id AS NVARCHAR(4)), 4) + N'_in')
                  ,(t.[name] + '_' + Right(N'0000' + Cast(@filial_id AS NVARCHAR(4)), 4) + N'_out')
            ) t2(NAME)
        WHERE si.type IN (
                --0
                 1
                ,2
                ,5
                ,6
                ) -- heap, clustered, nonclustered, CLUSTERED COLUMNSTORE, NONCLUSTERED COLUMNSTORE
            and t.schema_id = schema_id(N'dbo')
            and exists (Select 1 from [load].[tables_to_load] tl Where t.[name] = tl.[name])
        ORDER BY t2.NAME, index_create_statement
        FOR XML PATH(N''), TYPE
        ).value(N'.', N'NVARCHAR(MAX)');
 
exec(@sql);

А вот так переключаемся:
Кликните здесь для просмотра всего текста

T-SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Begin Tran -- переключим все таблицы разом
 
DECLARE @sql NVARCHAR(max) = N'';
 
-- Переключение партиции из целевой таблицы в таблицу out и in
Select @sql = (
    Select 
          'Alter table [dbo].' + QUOTENAME(aa.name) + ' switch partition ' + cast(p.num as varchar(255)) + ' to [tmp].' +  QUOTENAME(t2.NAME + N'_out')  + ' WITH (WAIT_AT_LOW_PRIORITY (MAX_DURATION = 1, ABORT_AFTER_WAIT = BLOCKERS));'
        + 'Alter table [tmp].' +  QUOTENAME(t2.NAME + N'_in') + ' switch to dbo.' + QUOTENAME(aa.name) + ' partition ' + cast(p.num as varchar(255)) + ' WITH (WAIT_AT_LOW_PRIORITY (MAX_DURATION = 1, ABORT_AFTER_WAIT = BLOCKERS));;'
        FROM 
        [load].[tables_to_load] aa
        Cross apply (Values ($partition.[fn_region_data](@filial_id))) p(num)
        Cross apply 
            (
            VALUES (aa.[name] + '_' + Right(N'0000' + Cast(@filial_id AS NVARCHAR(4)), 4))
            ) t2(NAME)
        For xml path(''), type).value(N'.', N'NVARCHAR(MAX)');
 
-- Т.к. возможно только одно переключение одновременно
-- установим эксклюзивную блокировку
exec sp_getapplock N'target', 'Exclusive', 'Transaction', -1;
 
exec(@sql);
 
-- Освободим защелку
exec sp_releaseapplock N'target', 'Transaction';
 
Commit



А вот это - создание констрейнтов. Констрейнты создаем уже после загрузки.
Кликните здесь для просмотра всего текста

T-SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
DECLARE @sql NVARCHAR(max) = N'';
-- Изменение параметров сжатия темповых таблиц, аналогично целевой таблице 
Select @sql += Coalesce((
    Select 
        ';Alter table [tmp].' + QUOTENAME(t2.NAME) + ' REBUILD PARTITION = ALL  WITH (DATA_COMPRESSION = ' + pt.data_compression_desc + ')'   
        FROM 
        sys.tables aa
        Cross apply (Values ($partition.[fn_region_data](@filial_id))) p(num)
        Cross apply 
            (
            VALUES (aa.[name] + '_' + Right(N'0000' + Cast(@filial_id AS NVARCHAR(4)), 4) +  N'_out')
            ) t2(NAME)
        inner join sys.partitions (nolock) pt on pt.partition_number = p.num and pt.object_id = aa.object_id  and pt.index_id = 1
        inner join sys.partitions (nolock) pt2 on pt2.object_id = object_id('tmp.' + t2.NAME) and pt2.index_id = 1
        WHERE aa.schema_id = schema_id(N'dbo') and pt.data_compression_desc <> pt2.data_compression_desc
              and exists(Select 1 from [load].[tables_to_load] a where a.[name] = aa.[name])
        For xml path(''), type).value(N'.', N'NVARCHAR(MAX)'), N'');
 
Select @sql += Coalesce((
    Select 
        ';Alter table [tmp].' + QUOTENAME(t2.NAME) + ' REBUILD PARTITION = ALL  WITH (DATA_COMPRESSION = ' + pt.data_compression_desc + ')'   
        FROM 
        sys.tables aa
        Cross apply (Values ($partition.[fn_region_data](@filial_id))) p(num)
        Cross apply 
            (
            VALUES (aa.[name] + '_' + Right(N'0000' + Cast(@filial_id AS NVARCHAR(4)), 4) + N'_in')
            ) t2(NAME)
        inner join sys.partitions (nolock) pt on pt.partition_number = p.num and pt.object_id = aa.object_id and pt.index_id = 1
        inner join sys.partitions (nolock) pt2 on pt2.object_id = object_id('tmp.' + t2.NAME) and pt2.index_id = 1
        WHERE aa.schema_id = schema_id(N'dbo') and pt.data_compression_desc <> pt2.data_compression_desc
              and exists(Select 1 from [load].[tables_to_load] a where a.[name] = aa.[name])
        For xml path(''), type).value(N'.', N'NVARCHAR(MAX)'), N'');
 
-- Создание констрейнтов, соответствующих партиции, только для in
Select @sql += Coalesce((
    Select 
        ';Alter table [tmp].' +  QUOTENAME(t2.NAME) + ' WITH CHECK ADD CONSTRAINT ' + Quotename('chk_' + t2.NAME) + ' CHECK ([filial_id] = ' + Cast(@filial_id as nvarchar(255)) + ')'
        FROM 
        sys.tables aa
        Cross apply 
            (
            VALUES (aa.[name] + '_' + Right(N'0000' + Cast(@filial_id AS NVARCHAR(4)), 4) + N'_in')
            ) t2(NAME)
        WHERE aa.schema_id = schema_id(N'dbo')
              and exists(Select 1 from [load].[tables_to_load] a where a.[name] = aa.[name])
        For xml path(''), type).value(N'.', N'NVARCHAR(MAX)'), N'');
 
exec(@sql);
2
932 / 365 / 43
Регистрация: 10.05.2021
Сообщений: 1,564
Записей в блоге: 10
27.06.2025, 13:58  [ТС]
uaggster, большое спасибо!
Непростая задачка, конечно
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
27.06.2025, 13:58
Помогаю со студенческими работами здесь

Секционирование
Всем привет! Помогите решить такую задачу! Есть таблица заказов клиентов, которую хочу секционировать, но по &quot;хитрому&quot;. Чтобы...

Для чего нужно писать в int main() в скобках всякие args потом объявлять переменные, и прочее. Для чего если можно в сборках это все обьявлять.
Для чего нужно писать в int main() в скобках всякие args потом объявлять переменные, и прочее. Для чего если можно в сборках это все...

Для чего нужен Seed() и для чего его override?
Привет, ребята. Прочитал много разных статей про Seed(). И так и не могу понять зачем он нужен на практике. Вот выдержка одной из...

Секционирование таблиц
Всем привет. Помогите разобраться с секционированием таблиц. Как с ныне существующей таблицы сделать секционированные. Разбить на...

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


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
14
Ответ Создать тему
Новые блоги и статьи
Ритм жизни
kumehtar 27.02.2026
Иногда приходится жить в ритме, где дел становится всё больше, а вовлечения в происходящее — всё меньше. Плотный график не даёт вниманию закрепиться ни на одном событии. Утро начинается с быстрых,. . .
[В процессе разработки] SDL3 для Web (WebAssembly): Сборка библиотек SDL3 и Box2D из исходников с помощью CMake и Emscripten
8Observer8 27.02.2026
Недавно вышла версия 3. 4. 2 библиотеки SDL3. На странице официальной релиза доступны исходники, готовые DLL (для x86, x64, arm64), а также библиотеки для разработки под Android, MinGW и Visual Studio. . . .
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru