четверг, 26 августа 2010 г.

Работа с партициями в MSAS 2008

 

Всем привет.

Сегодня хочу описать  небольшой скрипт, который я написал для работы с партициями MSAS.

Предыстория

У нас на предприятия есть отчетная система(язык не поворачивается назвать ее аналитической), построенная на основе MSAS. Так вот  в чем состояла наша проблема. Вытяжка в таблицу фактов за весь период работы предприятия была, есть и будет очень долго, где-то примерно 10 часов, поэтому чтоб не запускать ее каждый раз решили перейти к партициям в кубе. Каждый год у нас считается что-то типа закрытого периода, обновляются только текущий месяц и предыдущий. Остальные партиции  обновляются, только в случае непредвиденных обстоятельств. В MSAS все это выглядит вот так:

as1

Для каждой партиции указан источник:

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:    }

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

Комментариев нет: