### Description

Our most common aggregations should be optimized for single-valued fields. In general, our aggregations look like this:

```java
    @Override
    public LeafBucketCollector getLeafCollector(LeafReaderContext ctx, LeafBucketCollector sub) throws IOException {
        if (valuesSource == null) {
            return LeafBucketCollector.NO_OP_COLLECTOR;
        }
        SortedNumericDocValues values = valuesSource.longValues(ctx);
        return new LeafBucketCollectorBase(sub, values) {
            @Override
            public void collect(int doc, long owningBucketOrd) throws IOException {
                if (values.advanceExact(doc)) {
                    int valuesCount = values.docValueCount();
                    for (int i = 0; i < valuesCount; ++i) {
                        long value = values.nextValue();
                        // do something with value
                    }
                }
            }
        };
    }
```

The idea consists of optimizing for single-valued fields by unwrapping the single-valued doc-value iterator:

```java
    @Override
    public LeafBucketCollector getLeafCollector(LeafReaderContext ctx, LeafBucketCollector sub) throws IOException {
        if (valuesSource == null) {
            return LeafBucketCollector.NO_OP_COLLECTOR;
        }
        SortedNumericDocValues values = valuesSource.longValues(ctx);
        NumericDocValues singleValues = DocValues.unwrapSingleton(values); // or FieldData.unwrapSingleton for doubles
        if (singleValues != null) {
            return new LeafBucketCollectorBase(sub, values) {
                @Override
                public void collect(int doc, long owningBucketOrd) throws IOException {
                    if (singleValues.advanceExact(doc)) {
                        long value = singleValues.longValue();
                        // do something with value
                    }
                }
            };
        } else {
            return new LeafBucketCollectorBase(sub, values) {
                @Override
                public void collect(int doc, long owningBucketOrd) throws IOException {
                    if (values.advanceExact(doc)) {
                        int valuesCount = values.docValueCount();
                        for (int i = 0; i < valuesCount; ++i) {
                            long value = values.nextValue();
                            // do something with value
                        }
                    }
                }
            };
        }
    }
```

The `terms` aggregation already does this, and e.g. `min` and `max` aggregations use similar tricks that also help optimize the single-valued case. But `date_histogram`, which is one of our most common aggregations, doesn't. Let's specialize the single-value case for date histograms too?
server/src/internalClusterTest/java/org/elasticsearch/search/profile/aggregation/AggregationProfilerIT.java
BUILD_LEAF_COLLECTOR + "_count",
        COLLECT + "_count",
        POST_COLLECTION + "_count",
        BUILD_AGGREGATION + "_count",
        REDUCE + "_count"
    );
    private static final String TOTAL_BUCKETS = "total_buckets";
    private static final String BUILT_BUCKETS = "built_buckets";
    private static final String DEFERRED = "deferred_aggregators";
    private static final String COLLECTION_STRAT = "collection_strategy";
    private static final String RESULT_STRAT = "result_strategy";
    private static final String HAS_FILTER = "has_filter";
    private static final String SEGMENTS_WITH_SINGLE = "segments_with_single_valued_ords";
    private static final String SEGMENTS_WITH_MULTI = "segments_with_multi_valued_ords";
    private static final String NUMBER_FIELD = "number";
    private static final String TAG_FIELD = "tag";
    private static final String STRING_FIELD = "string_field";
    @Override
    protected int numberOfShards() {
        return 1;
    }
    @Override
    protected void setupSuiteScopeCluster() throws Exception {
        assertAcked(
            client().admin()
                .indices()
                .prepareCreate("idx")
                .setSettings(Map.of("number_of_shards", 1, "number_of_replicas", 0))
                .setMapping(STRING_FIELD, "type=keyword", NUMBER_FIELD, "type=integer", TAG_FIELD, "type=keyword")
                .get()