docs: public List<Query> optimize(Query query)
    {
      long start = System.currentTimeMillis();
      // only topN/timeseries/groupby query can be optimized
      // only TableDataSource can be optimiezed
      if (!(query instanceof TopNQuery || query instanceof TimeseriesQuery || query instanceof GroupByQuery)
          || !(query.getDataSource() instanceof TableDataSource)) {
        return Collections.singletonList(query);
      }
      String datasourceName = ((TableDataSource) query.getDataSource()).getName();
      // get all derivatives for datasource in query. The derivatives set is sorted by average size of 
      // per segment granularity.
      Set<DerivativeDataSource> derivatives = DerivativeDataSourceManager.getDerivatives(datasourceName);
      
      if (derivatives.isEmpty()) {
        return Collections.singletonList(query);
      }
      lock.readLock().lock();
      try {
        totalCount.putIfAbsent(datasourceName, new AtomicLong(0));
        hitCount.putIfAbsent(datasourceName, new AtomicLong(0));
        costTime.putIfAbsent(datasourceName, new AtomicLong(0));
        totalCount.get(datasourceName).incrementAndGet();
        
        // get all fields which the query required
        Set<String> requiredFields = MaterializedViewUtils.getRequiredFields(query);
        
        Set<DerivativeDataSource> derivativesWithRequiredFields = new HashSet<>();
        for (DerivativeDataSource derivativeDataSource : derivatives) {
          derivativesHitCount.putIfAbsent(derivativeDataSource.getName(), new AtomicLong(0));
          if (derivativeDataSource.getColumns().containsAll(requiredFields)) {
            derivativesWithRequiredFields.add(derivativeDataSource);
          }
        }
        // if no derivatives contains all required dimensions, this materialized view selection failed.
        if (derivativesWithRequiredFields.isEmpty()) {
          missFields.putIfAbsent(datasourceName, new ConcurrentHashMap<>());
          missFields.get(datasourceName).putIfAbsent(requiredFields, new AtomicLong(0));
          missFields.get(datasourceName).get(requiredFields).incrementAndGet();
          costTime.get(datasourceName).addAndGet(System.currentTimeMillis() - start);
          return Collections.singletonList(query);
        }
        
        List<Query> queries = new ArrayList<>();
        List<Interval> remainingQueryIntervals = (List<Interval>) query.getIntervals();
        
        for (DerivativeDataSource derivativeDataSource : ImmutableSortedSet.copyOf(derivativesWithRequiredFields)) {
          final List<Interval> derivativeIntervals = remainingQueryIntervals.stream()
              .flatMap(interval -> serverView
                  .getTimeline((new TableDataSource(derivativeDataSource.getName())))
                  .lookup(interval)
                  .stream()
                  .map(TimelineObjectHolder::getInterval)
              )
              .collect(Collectors.toList());
          // if the derivative does not contain any parts of intervals in the query, the derivative will
          // not be selected. 
          if (derivativeIntervals.isEmpty()) {
            continue;
          }
          
          remainingQueryIntervals = MaterializedViewUtils.minus(remainingQueryIntervals, derivativeIntervals);
          queries.add(
              query.withDataSource(new TableDataSource(derivativeDataSource.getName()))
                  .withQuerySegmentSpec(new MultipleIntervalSegmentSpec(derivativeIntervals))
          );
          derivativesHitCount.get(derivativeDataSource.getName()).incrementAndGet();
          if (remainingQueryIntervals.isEmpty()) {
            break;
          }
        }
  
        if (queries.isEmpty()) {
          costTime.get(datasourceName).addAndGet(System.currentTimeMillis() - start);
          return Collections.singletonList(query);
        }
  
        //after materialized view selection, the result of the remaining query interval will be computed based on
        // the original datasource. 
        if (!remainingQueryIntervals.isEmpty()) {
          queries.add(query.withQuerySegmentSpec(new MultipleIntervalSegmentSpec(remainingQueryIntervals)));
        }
        hitCount.get(datasourceName).incrementAndGet();
        costTime.get(datasourceName).addAndGet(System.currentTimeMillis() - start);
        return queries;
      } 
      finally {
        lock.readLock().unlock();
      }
    }