Другой диалект

Читаем ошибки BigQuery

10 мин
Чему научишься
  • читать анатомию ошибки BigQuery: класс, виновник, позиция [строка:символ]
  • расшифровывать Unrecognized name и подсказку Did you mean
  • разбирать простыню No matching signature: какой аргумент не подошёл и почему
  • по тексту ошибки определять класс отказа, находить место сбоя и выбирать первую проверку

Пакет с пометкой «отказ»

В очереди станции всплыл пакет: запросы, которые прежние операторы отправляли архиву годы назад. Все — с пометкой «отказ». Комендант хочет знать, что в них спрашивали: вдруг операторы искали то же, что и ты.

Открываешь первый — и видишь не данные, а ответ архива: несколько строк текста, координаты, перечень каких-то сигнатур. Архив не молчал. Он объяснял, что не так, — на своём языке.

КВЕРИ: Переводчика с языка отказов у меня нет — есть ты. В пакете пять запросов, отказы разные. Разберём все пять.

Ниша возвращённых пакетов: стойка старых капсул с красными печатями отказа. Курсант вскрыл одну, и она проецирует диагностическую голограмму из четырёх полос света, а тонкий луч указывает точное место в колоннах архива. Робот-кот держит печать в лапе.
Отказ архива — не стена, а объяснение: класс ошибки, виновник, позиция и подсказка читаются по частям.

Отказ №1: Unrecognized name

Первый запрос из пакета:

SELECT name, colonny
FROM fa_users
ORDER BY user_id;

Ответ архива:

Unrecognized name: colonny; Did you mean colony? [at 1:14]

Читаем по частям — порядок годится для любой ошибки BigQuery:

  1. Класс: Unrecognized name — такое имя (колонки или ) не найдено в области видимости запроса.
  2. Виновник: colonny — имя, как ты его написал.
  3. Подсказка: Did you mean colony? — BigQuery ищет похожее имя и чаще всего угадывает. Но это эвристика: при опечатке в две буквы подсказки может не быть, а иногда она предлагает похожую, но не ту колонку. Проверяй по схеме, а не на веру.
  4. Координаты: [at 1:14] — строка 1, символ 14 ТВОЕГО запроса. В запросе на сорок строк это главный навигатор.

Правка очевидна: colony. Ячейка ниже — уже починенная. Теперь поработай с архивом отказов сам: верни опечатку colonny, запусти и сверь текст ошибки с разобранным.

Как читать отказ BigQueryUnrecognized name: colonny;Did you mean colony? at [1:14]что случилосьподсказка — часто готовое лечениегде именно: строка и символ
В отказе три полезных части: что случилось, подсказка и координата в твоём запросе
Рабочая версия. Сломай её обратно — замени colony на colonny — и прочитай отказ архива своими глазами.

Отказ №2: Table not found

SELECT action, COUNT(*) AS n
FROM fa_logs_20291113
GROUP BY action;
Table not found: fa_logs_20291113 [at 2:6]

Класс говорит сам за себя: таблицы нет. У мигранта причины обычно три:

  • опечатка в имени — как с колонкой, только подсказка срабатывает реже;
  • не тот или проект: полный адрес — проект.датасет.таблица; в нём легко забыть бэктики, и тогда FROM my-project.logs.events разваливается на бессмысленное вычитание my - project;
  • таблицы действительно нет: наш журнал шардирован по дням — fa_logs_20291110, ..._11, ..._12. Запрос выше спрашивает шард за 13-е ноября, которого архив уже не записал.

И да: имена таблиц и датасетов в BigQuery чувствительны к региструFA_LOGS_20291112 и fa_logs_20291112 для архива разные имена (имена колонок и функций — нет).

Последний записанный день — 12-е ноября:

Последний шард журнала: три входа и одна синхронизация — 12 ноября 2029 года архив ещё жил.

Отказ №3: No matching signature — простыня, которая читается

Третий запрос пакета хотел посчитать выручку:

SELECT SUM(status) AS paid_total
FROM fa_orders
WHERE status = 'paid';
No matching signature for aggregate function SUM
  Argument types: STRING
  Signature: SUM(INT64)
    Argument 1: Unable to coerce type STRING to expected type INT64
  Signature: SUM(UINT64)
    Argument 1: Unable to coerce type STRING to expected type UINT64
  ...
  Signature: SUM(NUMERIC)
    Argument 1: Unable to coerce type STRING to expected type NUMERIC
  ... [at 1:8]

Выглядит стеной текста, но структура жёсткая:

  1. Класс: No matching signature — функция существует, но НЕ с такими типами аргументов.
  2. Что ты передал: Argument types: STRING.
  3. Список сигнатур — все варианты, которые функция принимает, и по каждому — какой аргумент не влез (Unable to coerce ...). Это не мусор, это список допустимого. Первый вопрос по нему — не «как привести тип», а «тот ли аргумент вообще уехал в функцию». Приводить тип имеет смысл, только когда аргумент верный, а сигнатура его действительно не принимает.

Здесь намерение — сумма по total, а в SUM уехала строковая status: оператор перепутал колонки. BigQuery, в отличие от MySQL, никогда не приводит строку к числу молча:

8901.16 кредитов по десяти оплаченным заказам — выручка станции снабжения за неделю.

Отказы №4 и №5: типы в функции и в операторе

Два последних запроса пакета ломаются одинаково — на типах. Они показаны рядом для сравнения, а координаты в сообщениях относятся к каждому запросу по отдельности, как если бы ты запускал его один:

-- №4: короткий номер заказа — «последние две цифры»
SELECT order_id, SUBSTR(order_id, 2, 2) AS short_id
FROM fa_orders;
-- No matching signature for function SUBSTR
--   Argument types: INT64, INT64, INT64
--   Signature: SUBSTR(STRING, INT64, [INT64])
--     Argument 1: Unable to coerce type INT64 to expected type STRING
--   ... [at 1:18]

-- №5: стыковочный сбор из строкового конфига
SELECT order_id, total + '25' AS with_docking_fee
FROM fa_orders;
-- No matching signature for operator +
--   Argument types: NUMERIC, STRING
--   ... [at 1:18]

Оба отказа — одна привычка мигранта: надежда на неявное приведение. SUBSTR по числу прощал MySQL; число + 'строка' прощают многие языки. BigQuery строг: приводи явно. В №4 намерение строковое — значит CAST(order_id AS STRING); в №5 числовое — значит CAST('25' AS NUMERIC).

Обе правки в одной ячейке:

Число → строка для SUBSTR, строка → число для сложения. Оба CAST безопасны: типы известны заранее, SAFE_CAST не нужен.
Три класса отказов — три разных действияимяUnrecognized nameопечатка или чужая колонкатаблицаNot found: Tableадрес из трёх имёнтипNo matching signatureаргумент не того типакласс отказа называет первую проверку
Класс отказа сразу называет первую проверку

Отказы, которых песочница не покажет

Пять разобранных отказов свелись к трём классам — неизвестное имя, отсутствующая таблица и несовпадение сигнатуры: архив (и наша песочница) находит их ещё ДО чтения данных, поэтому такие отказы бесплатны. В BigQuery есть отказы других уровней — у мигранта они вызывают оторопь:

  • биллинг и квоты: Quota exceeded и родня — запрос упёрся в лимиты проекта или в отключённый биллинг; чинится не правкой SQL, а настройками проекта;
  • партиционный фильтр: Cannot query over table ... without a filter over column(s) ... that can be used for partition elimination — владелец таблицы запретил дорогие запросы без фильтра по партиции; что это за механика — глава «Деньги и масштаб»;
  • предел ресурсов: Resources exceeded — запрос слишком прожорлив для выделенной памяти; частый виновник — ORDER BY всего журнала без LIMIT.

В песочнице их не воспроизвести — здесь нет ни биллинга, ни квот. Запомни сам факт: если текст отказа не про имена и не про типы — читай его как счёт или как запрет, а не как баг твоего SQL.

Проверь себя
Оператор прислал запрос SELECT SUM(total) AS credits_total FROM fa_payments и отказ: Unrecognized name: total [at 1:12]. В чём причина и какова минимальная правка?
Проверь себя
Отказ архива: No matching signature for operator + Argument types: NUMERIC, STRING ... на запросе SELECT total + '25' AS with_fee FROM fa_orders. Какая правка минимальна и сохраняет смысл?
Закрепление: реши задачи
Решено 0 из 3 · для зачёта достаточно 2
Главное из урока
КлассЧто значитПервая правка
Unrecognized name: x; Did you mean y?имя не найдено; подсказка — эвристикасверь имя со схемой; [row:col] приведёт к месту
Table not foundнет таблицы: опечатка, не тот /проект, регистрполный адрес в бэктиках; существует ли шард?
No matching signatureфункция есть, типы не тенайди в списке сигнатур своё намерение и приведи тип явно
Quota exceeded, Cannot query over table without a filter ...не баг SQL: квоты, биллинг, запрет дорогих запросовнастройки проекта; партиционный фильтр (глава 5)
  • координаты [at строка:символ] — навигатор по твоему запросу
  • BigQuery не приводит типы молча: явный CAST — часть

Документация: сообщения об ошибках, синтаксис запросов.

Глава закрыта: ты говоришь на диалекте, знаешь цену слов и читаешь отказы. Но КВЕРИ уже нашёл в журналах то, чего не понял: DATE_DIFF насчитал целый день там, где прошло два часа. Следующая глава — система типов и четыре вида времени: места, где интуиция Postgres врёт тише всего.