Всем привет.
Сегодня хочу описать небольшой скрипт, который я написал для работы с партициями MSAS.
Предыстория
У нас на предприятия есть отчетная система(язык не поворачивается назвать ее аналитической), построенная на основе MSAS. Так вот в чем состояла наша проблема. Вытяжка в таблицу фактов за весь период работы предприятия была, есть и будет очень долго, где-то примерно 10 часов, поэтому чтоб не запускать ее каждый раз решили перейти к партициям в кубе. Каждый год у нас считается что-то типа закрытого периода, обновляются только текущий месяц и предыдущий. Остальные партиции обновляются, только в случае непредвиденных обстоятельств. В MSAS все это выглядит вот так:
Для каждой партиции указан источник:
SELECT * FROM [dbo].[таблица] WHERE year(Дата)<=2004
То есть фактически каждая партиция содержит данные за определенный год. Что же касается текущего то, тут чуть другая ситуация.
Для текущего года, на картинки part_2010 источник другой
SELECT * FROM [dbo].[таблица]
WHERE
(Year(Дата)=2010 ) and ( (Month(Дата)>=1) and (Month(Дата)<=6))
а партиция prev содержит источник за предыдущий месяц и current за текущий.
Такая структура позволяет обновлять только 2 партиции(текущую и предыдущую) и отказаться от полного процессинга куба.
НО, 1 числа каждого месяца необходимо изменять источник и увеличивать диапазон в источнике данных партиции текущего года, как бы наращивать каждый месяц.
Задача
Необходимо написать скрипт, который бы создавал новую партицию и изменял бы в источнике данных запрос
Решение
Решением стал скрипт, написанный на C# с использованием AMO
1: public void Main()
2: {
3: // TODO: Add your code here
4: Dts.TaskResult = (int)GetAS();
5: }
6://создание партиции год
7: public bool CreatePartitionYear(Cube cubePartition)
8: {
9: Partition partYear = new Partition("part_" + DateTime.Now.Year.ToString());//создаем объект партиции и назвначаем ему имя
10: Microsoft.AnalysisServices.QueryBinding query = new QueryBinding();// создаем объект, отвечающий за источник
11: query.DataSourceID = cubePartition.DataSource.ID;//указываем id источника
12: partYear.StorageMode = StorageMode.Molap;//указываем тип партции
13: query.QueryDefinition = "SELECT * FROM [dbo].[таблица] WHERE (Year(Дата)=" + DateTime.Now.Year.ToString() + " ) and (Month(Дата)=1) ";//указываем собственно запрос
14: partYear.Source = query;// присваевается объект источника партиции
15: try
16: {
17: cubePartition.MeasureGroups[0].Partitions.Add(partYear);//добавляем партицию в куб
18: partYear.Update();//отправляем новое определение объекта на сервер
19: partYear.Update(UpdateOptions.AlterDependents);// на всякий случай
20: cubePartition.MeasureGroups[0].Update(UpdateOptions.AlterDependents);//обновляем структуру секций
21: cubePartition.Update();//обновляем структуру куба
22: cubePartition.Refresh();//делаем синхронизацию объектов Amo и as
23: cubePartition.MeasureGroups[0].Refresh();//делаем синхронизацию объектов Amo и as
24: }
25: catch (Exception exp)
26: {
27: return false;
28: }
30: Partition partNew;
32: partNew = cubePartition.MeasureGroups[0].Partitions.FindByName("prev");// ищем партицию prev
33: try
34: {
35: if (partNew != null) partNew.Drop();//если существуе, удаляем
36: }
37: catch (Exception exp)
38: {
40: }
41: partNew = cubePartition.MeasureGroups[0].Partitions.Add("prev");// добавляем партицию
42: partNew.StorageMode = StorageMode.Molap;// указываем тип партции
43: /создаем запрос для источника партиции
44: Microsoft.AnalysisServices.QueryBinding queryPrev = new QueryBinding();
45: queryPrev.QueryDefinition = "SELECT * FROM [dbo].[Таблица] WHERE (Year(Дата)=" + DateTime.Now.Year.ToString() + " ) and (Month(Дата)=" + (DateTime.Now.Month - 1).ToString() + ") ";
46: queryPrev.DataSourceID = cubePartition.DataSource.ID;
47: partNew.Source = queryPrev;
49: partNew.Update();//обновляем структур
50: cubePartition.MeasureGroups[0].Update(UpdateOptions.AlterDependents);//обновляем структуру секций
51: cubePartition.Update();//обновляем структуру куба
52: cubePartition.Refresh();//синхронизируем объекты
53: cubePartition.MeasureGroups[0].Refresh();//синхронизируем объекты
54: return true;
55: }
56: /создание партиции месяц
57: public bool CreatePartitionMonth(Cube cubePartition)
58: {
59: Partition part = cubePartition.MeasureGroups[0].Partitions.FindByName("part_" + DateTime.Now.Year.ToString());//ищем партцию текущего года
60: if (part != null)
61: {
62: Partition partPrev = cubePartition.MeasureGroups[0].Partitions.FindByName("prev");//ищем партицию prev
63: List<Partition> lspPart = new List<Partition>();//список партиций
64: Microsoft.AnalysisServices.QueryBinding query = new QueryBinding();//объект источник для партиции года
65: query.DataSourceID = cubePartition.DataSource.ID;
66: if ((DateTime.Now.Month == 1))//проверка на месяц
67: {
68: //Сделано для того, чтобы не возникала ситуация 1-2(текущий месяц январь(01, то есть 1), для вычисления месяца, который был 2 месяца назад, то есть 1-2=-1 и получаем exception. Да можно было бы от этого избавится и использовать функции месяца и вычислять минус 62 дня, но так наглядней и понятней
69: query.QueryDefinition = "SELECT * FROM [dbo].[таблица] WHERE (Year(Дата)=" + (DateTime.Now.Year-1).ToString() + " ) and (Month(Дата)=11) ";
70:
71: }
72: else
73: {
74: if ((DateTime.Now.Month == 2))//проверка на второй месяц.
75: {
76: query.QueryDefinition = "SELECT * FROM [dbo].[таблица] WHERE (Year(Дата)=" + (DateTime.Now.Year - 1).ToString() + " ) and (Month(Дата)=12) ";
77: }
78: else
79: {
80: query.QueryDefinition = "SELECT * FROM [dbo].[таблица] WHERE (Year(Дата)=" +
81: DateTime.Now.Year.ToString() + " ) and ((Month(Дата)>=1) and (Month(Дата)<=" + (DateTime.Now.Month - 2).ToString() + ")) ";
82: }
83: }
84: part.Source = query;
86: lspPart.Add(partPrev);
88: try
89: {
90: part.Merge(lspPart);//сливаем партиции
91: part.Update(UpdateOptions.AlterDependents);//обновляем структуру секции год
92: cubePartition.MeasureGroups[0].Update(UpdateOptions.AlterDependents);//обновляем структуру секций
93: cubePartition.Update();//обновляем структур куба
94: cubePartition.Refresh();//синхронизация
95: cubePartition.MeasureGroups[0].Refresh();//синхронизация
97: }
98: catch(Exception exp)
99: {
100: string message = exp.Message;
101: return false;
102: }
104: try
105: {
106: //здесь создаем партицию prev
107: Partition partNew;
108:
109: partNew =cubePartition.MeasureGroups[0].Partitions.FindByName("prev");
110: try
111: {
112: if (partNew != null) partNew.Drop();
113: }
114: catch (Exception exp)
115: {
116:
117: }
118: partNew = cubePartition.MeasureGroups[0].Partitions.Add("prev");
119: partNew.StorageMode = StorageMode.Molap;
120:
121: Microsoft.AnalysisServices.QueryBinding queryPrev = new QueryBinding();
122: queryPrev.QueryDefinition = "SELECT * FROM [dbo].[таблица] WHERE (Year(Дата)=" + DateTime.Now.Year.ToString() + " ) and (Month(Дата)=" + (DateTime.Now.Month - 1).ToString() + ") ";
123: queryPrev.DataSourceID = cubePartition.DataSource.ID;
124: partNew.Source = queryPrev;
126: partNew.Update();
127: cubePartition.MeasureGroups[0].Update(UpdateOptions.AlterDependents);
128: cubePartition.Update();
129: cubePartition.Refresh();
130: cubePartition.MeasureGroups[0].Refresh();
132: }
133: catch (Exception exp)
134: {
135: string message = exp.Message;
136: return false;
137: }
139: }
140: return true;
141: }
142:
143:/ /процессинг партиций
144: public bool ProccesPartition(Cube cubePartition)
145: {
146: Partition partPrev = cubePartition.MeasureGroups[0].Partitions.FindByName("prev");//ищем партицию
147: if (partPrev != null)
148: {
149: partPrev.Process(ProcessType.ProcessFull);//делаем полный процессинг
150: }
151: else
152: {
153: return false;
154: }
156: Partition parCurrent = cubePartition.MeasureGroups[0].Partitions.FindByName("current");//ищем партицию
157: if (parCurrent != null)
158: {
159: parCurrent.Process(ProcessType.ProcessFull);//полный процессинг
160:
161: }
162: else
163: {
164: return false;
165: }
167: return true;
169: }
170:
172: public int GetAS()
173: {
174: using(Server srv=new Server())
175: {
176: srv.Connect("localhost");//коннектимся к серверу
177: Database db = srv.Databases.GetByName("ИмяБазы");//конектимся к базе
178: if (db != null)
179: {
180: Cube cubeOverturn = db.Cubes.GetByName("ИмяКубика");//ищем кубик
181: if (cubeOverturn != null)
182: {
183: DateTime dt = DateTime.Now;//определяем текущее время
184: if (dt.Day == 1)
185: {
186: if (dt.Month == 3)
187: {
188: if (!CreatePartitionYear(cubeOverturn))//создаем партцию года
189: {
190: srv.Disconnect();
191: return (int)ScriptResults.Failure;
192: }
193: else
194: {
195: ProccesPartition(cubeOverturn);//процессим партиции
196: }
197: }
198: else
199: {
200: if (!CreatePartitionMonth(cubeOverturn))//создаем партиции месяца
201: {
202: /произошла ошибка
203: srv.Disconnect();//разрываем связь
204: return (int)ScriptResults.Failure;//возвращаем fail
205: }
206: else
207: {
208: ProccesPartition(cubeOverturn);//процессим
209: }
210: }
211: }
212: else
213: {
214: if (!ProccesPartition(cubeOverturn))//просто процессим
215: {
216: srv.Disconnect();
217: return (int)ScriptResults.Failure;
218: }
220: }
221: }
222: else
223: {
224: srv.Disconnect();
225: return (int)ScriptResults.Failure;
226: }
228: }
229: else
230: {
231: srv.Disconnect();
232: return (int)ScriptResults.Failure;
233: }
234: srv.Disconnect();
235: }
238: return (int)ScriptResults.Success;
239: }
242: }
Да, я знаю, что код можно было бы упростить. Сделать рефакторинг, но этот будет все потом(нет времени). Сейчас скрипт работает нормально на моей базе.
Комментариев нет:
Отправить комментарий