/** * Copyright (C) 2009-2013 FoundationDB, LLC * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.foundationdb.sql.optimizer.rule.cost; import com.foundationdb.ais.model.*; import com.foundationdb.qp.rowtype.IndexRowType; import com.foundationdb.qp.rowtype.RowType; import com.foundationdb.qp.rowtype.TableRowType; import com.foundationdb.server.types.TClass; import com.foundationdb.server.types.common.types.TBinary; import com.foundationdb.server.types.common.types.TString; import com.foundationdb.server.types.mcompat.mtypes.MNumeric; public abstract class TreeStatistics { public abstract long rowCount(); public abstract int rowWidth(); public abstract RowType rowType(); public static TreeStatistics forTable(TableRowType rowType, TableRowCounts tableRowCounts) { return new TableStatistics(rowType, tableRowCounts); } public static TreeStatistics forIndex(IndexRowType rowType, TableRowCounts tableRowCounts) { return rowType.index().isGroupIndex() ? new GroupIndexStatistics(rowType, tableRowCounts) : new TableIndexStatistics(rowType, tableRowCounts); } int fieldWidth(Column column) { TClass tclass = column.getType().typeClass(); if (tclass.hasFixedSerializationSize()) { if (tclass instanceof MNumeric) { return 8; // TODO: For compatibility with existing tests. } return tclass.fixedSerializationSize(); } if (tclass instanceof TString) { int length = ((TString)tclass).getFixedLength(); if (length < 0) { return (int)(column.getAverageStorageSize() * PLAUSIBLE_AVERAGE_VAR_USAGE); } else { return PLAUSIBLE_AVERAGE_BLOB_SIZE; } } if (tclass instanceof TBinary) { int length = ((TBinary)tclass).getDefaultLength(); if (length < 0) { return (int)(column.getAverageStorageSize() * PLAUSIBLE_AVERAGE_VAR_USAGE); } else { return PLAUSIBLE_AVERAGE_BLOB_SIZE; } } return (int)column.getAverageStorageSize(); } private static final int PLAUSIBLE_AVERAGE_BLOB_SIZE = 100000; private static final double PLAUSIBLE_AVERAGE_VAR_USAGE = 0.3; protected TreeStatistics(TableRowCounts tableRowCounts) { this.tableRowCounts = tableRowCounts; } protected final TableRowCounts tableRowCounts; private static class TableStatistics extends TreeStatistics { public long rowCount() { return tableRowCounts.getTableRowCount(rowType.table()); } @Override public int rowWidth() { // Columns int rowWidth = 0; for (Column column : rowType.table().getColumnsIncludingInternal()) { rowWidth += fieldWidth(column); } // Attempt to estimate hkey width for (HKeySegment segment : rowType().table().hKey().segments()) { // ordinal rowWidth += 1; for (HKeyColumn hKeyColumn : segment.columns()) { rowWidth += fieldWidth(hKeyColumn.column()); } } return rowWidth; } public RowType rowType() { return rowType; } public TableStatistics(TableRowType rowType, TableRowCounts tableRowCounts) { super(tableRowCounts); this.rowType = rowType; } private final TableRowType rowType; } private static abstract class IndexStatistics extends TreeStatistics { @Override public final RowType rowType() { return rowType; } @Override public final int rowWidth() { int rowWidth = 0; Index index = rowType.index(); for (IndexColumn indexColumn : index.getAllColumns()) { rowWidth += fieldWidth(indexColumn.getColumn()); } return rowWidth; } protected IndexStatistics(IndexRowType rowType, TableRowCounts tableRowCounts) { super(tableRowCounts); this.rowType = rowType; } protected final IndexRowType rowType; } private static class TableIndexStatistics extends IndexStatistics { public long rowCount() { TableIndex index = (TableIndex) rowType.index(); Table table = index.getTable(); return tableRowCounts.getTableRowCount(table); } public TableIndexStatistics(IndexRowType rowType, TableRowCounts tableRowCounts) { super(rowType, tableRowCounts); } } private static class GroupIndexStatistics extends IndexStatistics { public long rowCount() { GroupIndex index = (GroupIndex) rowType.index(); return tableRowCounts.getTableRowCount(index.leafMostTable()); } public GroupIndexStatistics(IndexRowType rowType, TableRowCounts tableRowCounts) { super(rowType, tableRowCounts); } } }