Почему Apache Calcite оценивает 100 строк для всех таблиц, содержащихся в запросе? - PullRequest
0 голосов
/ 16 февраля 2019

Я недавно пытался выполнить запрос в Apache Calcite, используя три CSV-файла в качестве таблиц

  • TTLA_ONE содержит 59 строк
  • TTLR_ONE содержит 61390 строк
  • EMPTY_T содержит0 строк

Это запрос, который выполняется:

EXPLAIN PLAN FOR SELECT COUNT(*) as NUM 
FROM TTLA_ONE A 
INNER JOIN TTLR_ONE B1 ON A.X = B1.X
INNER JOIN TTLR_ONE B2 ON B2.X = B1.X
INNER JOIN EMPTY_T C1 ON C1.X = B2.Y
INNER JOIN EMPTY_T C2 ON C2.X = C2.X

Результат запроса всегда равен нулю, потому что мы соединяемся с пустой таблицей.Полученный план:

EnumerableAggregate(group=[{}], NUM=[COUNT()])
  EnumerableJoin(condition=[=($1, $4)], joinType=[inner])
    EnumerableJoin(condition=[=($0, $1)], joinType=[inner])
      EnumerableInterpreter
        BindableTableScan(table=[[STYPES, TTLA_ONE]])
      EnumerableCalc(expr#0..1=[{inputs}], X=[$t0])
        EnumerableInterpreter
          BindableTableScan(table=[[STYPES, TTLR_ONE]])
    EnumerableJoin(condition=[=($1, $3)], joinType=[inner])
      EnumerableJoin(condition=[true], joinType=[inner])
        EnumerableCalc(expr#0=[{inputs}], expr#1=[IS NOT NULL($t0)], X=[$t0], $condition=[$t1])
          EnumerableInterpreter
            BindableTableScan(table=[[STYPES, EMPTY_T]])
        EnumerableInterpreter
          BindableTableScan(table=[[STYPES, EMPTY_T]])
      EnumerableInterpreter
        BindableTableScan(table=[[STYPES, TTLR_ONE]])

Можно отметить, что пустые таблицы используются в плане в самом конце.

Я добавляю пример к этому тестовому коду .

Я копаю больше в коде и включаю журнал для отладки, и я вижу, что во всех таблицах строкиоцениваются как 100, но это не так.

Ниже, можно найти оценку плана с журналами, установленными в режиме отладки:

  EnumerableJoin(condition=[=($1, $4)], joinType=[inner]): rowcount = 3.0375E7, cumulative cost = {3.075002214917643E7 rows, 950.0 cpu, 0.0 io}, id = 26284
EnumerableJoin(condition=[=($0, $1)], joinType=[inner]): rowcount = 1500.0, cumulative cost = {2260.517018598809 rows, 400.0 cpu, 0.0 io}, id = 26267
  EnumerableInterpreter: rowcount = 100.0, cumulative cost = {50.0 rows, 50.0 cpu, 0.0 io}, id = 26260
    BindableTableScan(table=[[STYPES, TTLA_ONE]]): rowcount = 100.0, cumulative cost = {1.0 rows, 1.01 cpu, 0.0 io}, id = 7789
  EnumerableCalc(expr#0..1=[{inputs}], X=[$t0]): rowcount = 100.0, cumulative cost = {150.0 rows, 350.0 cpu, 0.0 io}, id = 26290
    EnumerableInterpreter: rowcount = 100.0, cumulative cost = {50.0 rows, 50.0 cpu, 0.0 io}, id = 26263
      BindableTableScan(table=[[STYPES, TTLR_ONE]]): rowcount = 100.0, cumulative cost = {1.0 rows, 1.01 cpu, 0.0 io}, id = 7791
EnumerableJoin(condition=[=($1, $3)], joinType=[inner]): rowcount = 135000.0, cumulative cost = {226790.8015771949 rows, 550.0 cpu, 0.0 io}, id = 26282
  EnumerableJoin(condition=[true], joinType=[inner]): rowcount = 9000.0, cumulative cost = {9695.982870329724 rows, 500.0 cpu, 0.0 io}, id = 26277
    EnumerableCalc(expr#0=[{inputs}], expr#1=[IS NOT NULL($t0)], X=[$t0], $condition=[$t1]): rowcount = 90.0, cumulative cost = {140.0 rows, 450.0 cpu, 0.0 io}, id = 26288
      EnumerableInterpreter: rowcount = 100.0, cumulative cost = {50.0 rows, 50.0 cpu, 0.0 io}, id = 26270
        BindableTableScan(table=[[STYPES, EMPTY_T]]): rowcount = 100.0, cumulative cost = {1.0 rows, 1.01 cpu, 0.0 io}, id = 7787
    EnumerableInterpreter: rowcount = 100.0, cumulative cost = {50.0 rows, 50.0 cpu, 0.0 io}, id = 26275
      BindableTableScan(table=[[STYPES, EMPTY_T]]): rowcount = 100.0, cumulative cost = {1.0 rows, 1.01 cpu, 0.0 io}, id = 7787
  EnumerableInterpreter: rowcount = 100.0, cumulative cost = {50.0 rows, 50.0 cpu, 0.0 io}, id = 26280
    BindableTableScan(table=[[STYPES, TTLR_ONE]]): rowcount = 100.0, cumulative cost = {1.0 rows, 1.01 cpu, 0.0 io}, id = 7791

Мы определенно можем видеть, что длядля каждой таблицы оценка всегда равна 100 rowcount = 100.0.

. Запрос выполняется правильно, но план не оптимизирован.Кто-нибудь знает, почему статистика таблицы не оценивается правильно?

Ответы [ 2 ]

0 голосов
/ 18 февраля 2019

Проблема в том, что в классе CsvTable необходимо переопределить метод свойства getStatistic, выполнив что-то вроде этого:

 private Statistic statistic;
 // todo: assign statistics  

  @Override
  public Statistic getStatistic() {
    return statistic;
  }

может передать эти статистические данные из конструктора или ввести некоторыеобъект, который их генерирует.

На данный момент возвращается просто Statistics.UNKNOWN, что находится в реализации суперкласса AbstractTable`.Конечно, без статистики оценочная стоимость плана неверна.

0 голосов
/ 18 февраля 2019

Ответ здесь такой же, как и для вопросов, уже связанных с комментариями.

Flink (пока) не переупорядочивает объединения

В текущей версии (1.7.1, Январь 2019), ... Calcite использует значение по умолчанию, равное 100.

Таким образом, план выполнения не ищет таблицы с нулевыми строками.В частности, из этих ответов я подозреваю, что даже если вы переупорядочите таблицы в предложении FROM, он все равно не заметит.

В целом, оптимизация SQL определяется наличием индексов кактак же, как по количеству таблиц.

Единственный способ ввести оценки количества элементов для таблиц - это через ExternalCatalog.

Вы это делаете?

Если вы загружаетеэти таблицы в виде CSV-файлов, декларируете ли вы ключи и индексы, а также другие материалы, необходимые для каталога?

Похоже, что Calcite не является зрелым продуктом.Если вы ищете испытательный стенд для проверки оптимизации SQL / плана запросов, используйте другой продукт.

...