← Назад к вопросам

Что такое OLAP?

2.3 Middle🔥 71 комментариев
#Базы данных и SQL

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

OLAP: Online Analytical Processing

OLAP (Online Analytical Processing) — это технология для анализа больших объёмов данных из различных перспектив (измерений). Это противоположность OLTP (Online Transaction Processing), которая оптимизирована для быстрых операций чтения-записи отдельных записей. OLAP предназначена для сложного анализа и отчётности.

OLAP vs OLTP

OLTP (Online Transaction Processing)

// OLTP ориентирован на ОПЕРАЦИИ (insert, update, delete)
// Пример: банковская операция

public class BankingService {
    
    @Transactional
    public void transferMoney(Long fromAccount, Long toAccount, BigDecimal amount) {
        Account from = accountRepository.findById(fromAccount)
            .orElseThrow();
        Account to = accountRepository.findById(toAccount)
            .orElseThrow();
        
        from.setBalance(from.getBalance().subtract(amount));
        to.setBalance(to.getBalance().add(amount));
        
        accountRepository.save(from);
        accountRepository.save(to);
        
        transactionRepository.save(new Transaction(from, to, amount));
    }
}

// Характеристики OLTP:
// - Много операций записи
// - Быстрые ответы (< 1 сек)
// - Нормализованные таблицы (чтобы избежать дублирования)
// - Маленькие запросы
// - Консистентность критична (ACID)

OLAP (Online Analytical Processing)

// OLAP ориентирован на АНАЛИЗ данных
// Пример: анализ финансовых тенденций

public class FinancialAnalyticsService {
    
    public void analyzeTrendsForQuarter(Quarter quarter) {
        // Запрос охватывает ВСЕ данные за квартал
        // 
        // SELECT date, branch, product_category,
        //        SUM(amount) as total_sales,
        //        COUNT(*) as transaction_count,
        //        AVG(amount) as avg_transaction
        // FROM transactions
        // WHERE quarter = '2024-Q1'
        // GROUP BY date, branch, product_category
        // ORDER BY total_sales DESC
        
        List<SalesMetrics> metrics = analyticsRepository
            .aggregateByDateBranchProduct(quarter);
        
        generateReport(metrics);
    }
}

// Характеристики OLAP:
// - Много операций чтения
// - Долгие запросы (от сек до часов)
// - Денормализованные таблицы (для быстроты)
// - Большие запросы (миллионы строк)
// - Консистентность в реальном времени не критична

Архитектура OLAP

Типичная структура Data Warehouse

Операционные БД (OLTP)  →  ETL (Extract, Transform, Load)  →  Data Warehouse (OLAP)
                                                                      ↓
                                                            Fact Tables + Dimension Tables
                                                                      ↓
                                                              OLAP Куб / BI Tools
                                                                      ↓
                                                              Отчёты и Аналитика

Star Schema (звездная схема)

// Dimension Tables (Справочники)
@Entity
public class DateDimension {
    @Id
    private Integer dateKey;  // 20240315
    private LocalDate date;
    private Integer dayOfWeek;
    private Integer week;
    private Integer month;
    private Integer quarter;
    private Integer year;
}

@Entity
public class ProductDimension {
    @Id
    private Integer productKey;
    private String productName;
    private String category;
    private String subcategory;
    private BigDecimal basePrice;
}

@Entity
public class BranchDimension {
    @Id
    private Integer branchKey;
    private String branchName;
    private String city;
    private String region;
    private String country;
}

// Fact Table (Таблица фактов)
@Entity
public class SalesFactTable {
    @Id
    private Long salesKey;
    
    // Foreign Keys на Dimensions
    @ManyToOne
    private DateDimension dateKey;
    
    @ManyToOne
    private ProductDimension productKey;
    
    @ManyToOne
    private BranchDimension branchKey;
    
    // Measurable Values (меры)
    private Long quantitySold;
    private BigDecimal salesAmount;  // сумма
    private BigDecimal discount;
    private BigDecimal profitAmount;  // прибыль
    private Integer transactionCount;
}

// Это позволяет быстро анализировать:
// - Продажи по времени (дата, месяц, квартал, год)
// - Продажи по продукту (категория, название)
// - Продажи по филиалу (город, регион)
// - Все комбинации выше (многомерный анализ)

Примеры OLAP запросов

1. Простая агрегация

-- "Какие продажи были в Москве в 2024 году?"
SELECT 
    pd.product_name,
    SUM(sf.sales_amount) as total_sales,
    SUM(sf.quantity_sold) as total_quantity,
    COUNT(*) as transaction_count
FROM sales_fact_table sf
JOIN date_dimension dd ON sf.date_key = dd.date_key
JOIN product_dimension pd ON sf.product_key = pd.product_key
JOIN branch_dimension bd ON sf.branch_key = bd.branch_key
WHERE bd.city = 'Moscow' AND dd.year = 2024
GROUP BY pd.product_name
ORDER BY total_sales DESC;

2. Временной анализ (temporal analysis)

-- "Как менялись продажи по месяцам в 2024 году?"
SELECT 
    dd.month,
    dd.month_name,
    SUM(sf.sales_amount) as monthly_sales,
    LAG(SUM(sf.sales_amount)) OVER (ORDER BY dd.month) as prev_month_sales,
    ROUND(
        (SUM(sf.sales_amount) - LAG(SUM(sf.sales_amount)) OVER (ORDER BY dd.month)) 
        / LAG(SUM(sf.sales_amount)) OVER (ORDER BY dd.month) * 100,
        2
    ) as growth_percent
FROM sales_fact_table sf
JOIN date_dimension dd ON sf.date_key = dd.date_key
WHERE dd.year = 2024
GROUP BY dd.month, dd.month_name
ORDER BY dd.month;

3. Многомерный анализ (drill-down)

-- Уровень 1: общие продажи по регионам
SELECT 
    bd.region,
    SUM(sf.sales_amount) as regional_sales
FROM sales_fact_table sf
JOIN branch_dimension bd ON sf.branch_key = bd.branch_key
GROUP BY bd.region;

-- Уровень 2: детализация по городам в выбранном регионе
SELECT 
    bd.city,
    SUM(sf.sales_amount) as city_sales
FROM sales_fact_table sf
JOIN branch_dimension bd ON sf.branch_key = bd.branch_key
WHERE bd.region = 'Western'
GROUP BY bd.city;

-- Уровень 3: детализация по продуктам в выбранном городе
SELECT 
    pd.product_name,
    SUM(sf.sales_amount) as product_sales
FROM sales_fact_table sf
JOIN branch_dimension bd ON sf.branch_key = bd.branch_key
JOIN product_dimension pd ON sf.product_key = pd.product_key
WHERE bd.city = 'Moscow'
GROUP BY pd.product_name;

Java реализация OLAP запросов

Spring Data JPA

@Repository
public interface SalesFactRepository extends 
    JpaRepository<SalesFact, Long>,
    JpaSpecificationExecutor<SalesFact> {}

@Service
public class OlapAnalyticsService {
    
    private final SalesFactRepository salesRepository;
    
    // Простая агрегация
    public List<SalesMetrics> getSalesByRegion(Integer year) {
        Specification<SalesFact> spec = (root, query, cb) -> {
            Join<SalesFact, DateDimension> dateJoin = 
                root.join("dateKey");
            Join<SalesFact, BranchDimension> branchJoin = 
                root.join("branchKey");
            
            return cb.equal(dateJoin.get("year"), year);
        };
        
        return salesRepository.findAll(spec).stream()
            .collect(Collectors.groupingBy(
                s -> s.getBranchKey().getRegion(),
                Collectors.summingBigDecimal(SalesFact::getSalesAmount)
            ))
            .entrySet().stream()
            .map(e -> new SalesMetrics(e.getKey(), e.getValue()))
            .collect(Collectors.toList());
    }
}

Native Query для сложных OLAP запросов

@Repository
public interface OlapQueryRepository {
    
    @Query(nativeQuery = true, value = 
        "SELECT " +
        "  dd.month_name as period, " +
        "  bd.region as region, " +
        "  pd.category as category, " +
        "  SUM(sf.sales_amount) as total_sales, " +
        "  SUM(sf.quantity_sold) as total_quantity, " +
        "  AVG(sf.sales_amount) as avg_sale " +
        "FROM sales_fact_table sf " +
        "JOIN date_dimension dd ON sf.date_key = dd.date_key " +
        "JOIN branch_dimension bd ON sf.branch_key = bd.branch_key " +
        "JOIN product_dimension pd ON sf.product_key = pd.product_key " +
        "WHERE dd.year = :year " +
        "GROUP BY dd.month_name, bd.region, pd.category " +
        "ORDER BY dd.month, bd.region, pd.category")
    List<SalesReport> getDetailedSalesReport(@Param("year") Integer year);
}

public interface SalesReport {
    String getPeriod();
    String getRegion();
    String getCategory();
    BigDecimal getTotalSales();
    Long getTotalQuantity();
    BigDecimal getAvgSale();
}

Типы OLAP архитектур

1. MOLAP (Multidimensional OLAP)

Использует: специализированные OLAP базы данных (как Essbase, Analysis Services)
Данные хранятся в многомерных кубах
Отличная производительность при запросах
Нужны дополнительные лицензии

2. ROLAP (Relational OLAP)

// Использует: обычные реляционные БД (PostgreSQL, MySQL)
// ROLAP генерирует SQL запросы на лету
// Это то, что обычно используется в Java приложениях

public class RolapGenerator {
    
    public String generateOlapQuery(
            List<String> dimensions,
            List<String> measures,
            Map<String, Object> filters) {
        
        StringBuilder sql = new StringBuilder();
        sql.append("SELECT ");
        
        // Добавляем dimensions
        dimensions.forEach(d -> sql.append(d).append(", "));
        
        // Добавляем measures (агрегации)
        measures.forEach(m -> sql.append("SUM(").append(m).append("), "));
        
        sql.append("FROM fact_table ");
        
        // Добавляем фильтры
        filters.forEach((k, v) -> 
            sql.append("WHERE ").append(k).append(" = '").append(v).append("' ")
        );
        
        // GROUP BY dimensions
        sql.append("GROUP BY ");
        dimensions.forEach(d -> sql.append(d).append(", "));
        
        return sql.toString();
    }
}

3. HOLAP (Hybrid OLAP)

Комбинирует MOLAP и ROLAP
Детальные данные хранятся в реляционной БД (ROLAP)
Агрегированные данные кэшируются в многомерных кубах (MOLAP)
Лучше производительность

OLAP операции

1. SLICE - выбрать значение по одному измерению
   Пример: все данные за март

2. DICE - выбрать значения по нескольким измерениям
   Пример: все данные за март по категориям A и B

3. DRILL-DOWN - перейти с более высокого уровня на более детальный
   Пример: От года к месяцам

4. ROLL-UP - агрегировать данные на более высокий уровень
   Пример: От месяцев к кварталам

5. PIVOT - переупорядочить оси куба
   Пример: Переместить регионы с строк на столбцы

Когда использовать OLAP

// ✅ Подходит для OLAP:
- Анализ исторических данных
- Отчёты и BI (Business Intelligence)
- Data Mining
- Финансовый анализ
- Маркетинг аналитика
- Регуляторная отчётность

// ❌ Не подходит для OLAP:
- Текущие операции (используй OLTP)
- Real-time системы
- Высоконагруженные операции записи

Заключение

OLAP — это мощный инструмент для анализа больших объёмов данных:

  • Data Warehouse хранит исторические данные
  • Star Schema структурирует данные для быстрого анализа
  • OLAP куб позволяет анализировать данные с разных углов
  • Java приложения обычно используют ROLAP подход
  • BI инструменты (Tableau, Power BI) работают с OLAP кубами