Перейти к основному содержимому
Версия: 2.0.x

Устранение неполадок асинхронных материализованных представлений

В этом разделе описано, как проверять асинхронные материализованные представления и решать проблемы, с которыми вы можете столкнуться при работе с ними.

ВНИМАНИЕ

Некоторые функции, показанные ниже, поддерживаются только начиная с Selena v1.5.2.

Проверка асинхронного материализованного представления

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

Проверка рабочего состояния асинхронного материализованного представления

Вы можете проверить рабочее состояние асинхронного материализованного представления с помощью SHOW MATERIALIZED VIEWS. Среди всей возвращаемой информации обратите внимание на следующие поля:

  • is_active: Активно ли состояние материализованного представления. Только активное материализованное представление может использоваться для ускорения запросов и их перезаписи.
  • last_refresh_state: Состояние последнего обновления, включая PENDING, RUNNING, FAILED и SUCCESS.
  • last_refresh_error_message: Причина сбоя последнего обновления (если состояние материализованного представления неактивно).
  • rows: Количество строк данных в материализованном представлении. Обратите внимание, что это значение может отличаться от фактического количества строк материализованного представления, поскольку обновления могут быть отложены.

Подробную информацию о других возвращаемых полях см. в SHOW MATERIALIZED VIEWS - Returns.

Пример:

MySQL > SHOW MATERIALIZED VIEWS LIKE 'mv_pred_2'\G
***************************[ 1. row ]***************************
id | 112517
database_name | ssb_1g
name | mv_pred_2
refresh_type | ASYNC
is_active | true
inactive_reason | <null>
partition_type | UNPARTITIONED
task_id | 457930
task_name | mv-112517
last_refresh_start_time | 2023-08-04 16:46:50
last_refresh_finished_time | 2023-08-04 16:46:54
last_refresh_duration | 3.996
last_refresh_state | SUCCESS
last_refresh_force_refresh | false
last_refresh_start_partition |
last_refresh_end_partition |
last_refresh_base_refresh_partitions | {}
last_refresh_mv_refresh_partitions |
last_refresh_error_code | 0
last_refresh_error_message |
rows | 0
text | CREATE MATERIALIZED VIEW `mv_pred_2` (`lo_quantity`, `lo_revenue`, `sum`)
DISTRIBUTED BY HASH(`lo_quantity`, `lo_revenue`) BUCKETS 2
REFRESH ASYNC
PROPERTIES (
"replication_num" = "3",
"storage_medium" = "HDD"
)
AS SELECT `lineorder`.`lo_quantity`, `lineorder`.`lo_revenue`, sum(`lineorder`.`lo_tax`) AS `sum`
FROM `ssb_1g`.`lineorder`
WHERE `lineorder`.`lo_linenumber` = 1
GROUP BY 1, 2;

1 row in set
Time: 0.003s

Просмотр истории обновлений асинхронного материализованного представления

Вы можете просмотреть историю обновлений асинхронного материализованного представления, запросив таблицу task_runs в базе данных information_schema. Среди всей возвращаемой информации обратите внимание на следующие поля:

  • CREATE_TIME и FINISH_TIME: Время начала и окончания задачи обновления.
  • STATE: Состояние задачи обновления, включая PENDING, RUNNING, FAILED и SUCCESS.
  • ERROR_MESSAGE: Причина сбоя задачи обновления.

Пример:

MySQL > SELECT * FROM information_schema.task_runs WHERE task_name ='mv-112517' \G
***************************[ 1. row ]***************************
QUERY_ID | 7434cee5-32a3-11ee-b73a-8e20563011de
TASK_NAME | mv-112517
CREATE_TIME | 2023-08-04 16:46:50
FINISH_TIME | 2023-08-04 16:46:54
STATE | SUCCESS
DATABASE | ssb_1g
EXPIRE_TIME | 2023-08-05 16:46:50
ERROR_CODE | 0
ERROR_MESSAGE | <null>
PROGRESS | 100%
EXTRA_MESSAGE | {"forceRefresh":false,"mvPartitionsToRefresh":[],"refBasePartitionsToRefreshMap":{},"basePartitionsToRefreshMap":{}}
PROPERTIES | {"FORCE":"false"}
***************************[ 2. row ]***************************
QUERY_ID | 72dd2f16-32a3-11ee-b73a-8e20563011de
TASK_NAME | mv-112517
CREATE_TIME | 2023-08-04 16:46:48
FINISH_TIME | 2023-08-04 16:46:53
STATE | SUCCESS
DATABASE | ssb_1g
EXPIRE_TIME | 2023-08-05 16:46:48
ERROR_CODE | 0
ERROR_MESSAGE | <null>
PROGRESS | 100%
EXTRA_MESSAGE | {"forceRefresh":true,"mvPartitionsToRefresh":["mv_pred_2"],"refBasePartitionsToRefreshMap":{},"basePartitionsToRefreshMap":{"lineorder":["lineorder"]}}
PROPERTIES | {"FORCE":"true"}

Мониторинг потребления ресурсов асинхронным материализованным представлением

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

Мониторинг потребления ресурсов во время обновления

Во время выполнения задачи обновления вы можете отслеживать его потребление ресурсов в реальном времени с помощью SHOW PROC '/current_queries'.

Среди всей возвращаемой информации обратите внимание на следующие поля:

  • ScanBytes: Размер отсканированных данных.
  • ScanRows: Количество отсканированных строк данных.
  • MemoryUsage: Объем используемой памяти.
  • CPUTime: Затраченное время CPU.
  • ExecTime: Время выполнения запроса.

Пример:

MySQL > SHOW PROC '/current_queries'\G
***************************[ 1. row ]***************************
StartTime | 2023-08-04 17:01:30
QueryId | 806eed7d-32a5-11ee-b73a-8e20563011de
ConnectionId | 0
Database | ssb_1g
User | root
ScanBytes | 70.981 MB
ScanRows | 6001215 rows
MemoryUsage | 73.748 MB
DiskSpillSize | 0.000
CPUTime | 2.515 s
ExecTime | 2.583 s

Анализ потребления ресурсов после обновления

После выполнения задачи обновления вы можете проанализировать потребление ресурсов через профили запросов. Вы можете просмотреть профиль задачи обновления материализованного представления через веб-интерфейс узла Leader FE кластера.

Когда асинхронное материализованное представление обновляется, выполняется оператор INSERT OVERWRITE. Вы можете проверить соответствующий профиль запроса, чтобы проанализировать время и ресурсы, затраченные задачей обновления.

Среди всей возвращаемой информации обратите внимание на следующие метрики:

  • Total: Общее время, затраченное запросом.
  • QueryCpuCost: Общее время CPU, затраченное запросом. Время CPU агрегируется для параллельных процессов. В результате значение этой метрики может быть больше фактического времени выполнения запроса.
  • QueryMemCost: Общая стоимость памяти запроса.
  • Другие метрики для отдельных операторов, таких как операторы join и агрегирования.

Подробную информацию о том, как проверить профиль запроса и понять другие метрики, см. в Analyze query profile.

Проверка, перезаписываются ли запросы асинхронным материализованным представлением

Вы можете проверить, может ли запрос быть перезаписан с помощью асинхронного материализованного представления из его плана запроса, используя EXPLAIN.

Если метрика SCAN в плане запроса показывает имя соответствующего материализованного представления, запрос был перезаписан материализованным представлением.

Пример 1:

MySQL > SHOW CREATE TABLE mv_agg\G
***************************[ 1. row ]***************************
Materialized View | mv_agg
Create Materialized View | CREATE MATERIALIZED VIEW `mv_agg` (`c_custkey`)
DISTRIBUTED BY RANDOM
REFRESH ASYNC
PROPERTIES (
"replication_num" = "3",
"replicated_storage" = "true",
"storage_medium" = "HDD"
)
AS SELECT `customer`.`c_custkey`
FROM `ssb_1g`.`customer`
GROUP BY `customer`.`c_custkey`;

MySQL > EXPLAIN LOGICAL SELECT `customer`.`c_custkey`
-> FROM `ssb_1g`.`customer`
-> GROUP BY `customer`.`c_custkey`;
+-----------------------------------------------------------------------------------+
| Explain String |
+-----------------------------------------------------------------------------------+
| - Output => [1:c_custkey] |
| - SCAN [mv_agg] => [1:c_custkey] |
| Estimates: {row: 30000, cpu: ?, memory: ?, network: ?, cost: 15000.0} |
| partitionRatio: 1/1, tabletRatio: 12/12 |
| 1:c_custkey := 10:c_custkey |
+-----------------------------------------------------------------------------------+

Если вы отключите функцию перезаписи запросов, Selena примет обычный план запроса.

Пример 2:

MySQL > SET enable_materialized_view_rewrite = false;
MySQL > EXPLAIN LOGICAL SELECT `customer`.`c_custkey`
-> FROM `ssb_1g`.`customer`
-> GROUP BY `customer`.`c_custkey`;
+---------------------------------------------------------------------------------------+
| Explain String |
+---------------------------------------------------------------------------------------+
| - Output => [1:c_custkey] |
| - AGGREGATE(GLOBAL) [1:c_custkey] |
| Estimates: {row: 15000, cpu: ?, memory: ?, network: ?, cost: 120000.0} |
| - SCAN [mv_bitmap] => [1:c_custkey] |
| Estimates: {row: 60000, cpu: ?, memory: ?, network: ?, cost: 30000.0} |
| partitionRatio: 1/1, tabletRatio: 12/12 |
+---------------------------------------------------------------------------------------+

Диагностика и решение проблем

Здесь мы перечислим некоторые распространенные проблемы, с которыми вы можете столкнуться при работе с асинхронным материализованным представлением, и соответствующие решения.

Сбой создания материализованного представления

Если вы не смогли создать асинхронное материализованное представление, то есть оператор CREATE MATERIALIZED VIEW не может быть выполнен, рассмотрите следующие аспекты:

  • Проверьте, не использовали ли вы по ошибке оператор SQL для синхронных материализованных представлений.

    Selena предоставляет два различных материализованных представления: синхронное материализованное представление и асинхронное материализованное представление.

    Базовый оператор SQL, используемый для создания синхронного материализованного представления, выглядит следующим образом:

    CREATE MATERIALIZED VIEW <mv_name>
    AS <query>

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

    CREATE MATERIALIZED VIEW <mv_name>
    REFRESH ASYNC -- Стратегия обновления асинхронного материализованного представления.
    DISTRIBUTED BY HASH(<column>) -- Стратегия распределения данных асинхронного материализованного представления.
    AS <query>

    Помимо оператора SQL, основное различие между двумя материализованными представлениями заключается в том, что асинхронные материализованные представления поддерживают весь синтаксис запросов, предоставляемый Selena, но синхронные материализованные представления поддерживают только ограниченный выбор агрегатных функций.

  • Проверьте, указали ли вы правильный столбец partitioning.

    При создании асинхронного материализованного представления вы можете указать стратегию partitioning, которая позволяет обновлять материализованное представление на более детальном уровне.

    В настоящее время Selena поддерживает только range partitioning и поддерживает только ссылку на один столбец из выражения SELECT в операторе запроса, который используется для создания материализованного представления. Вы можете использовать функцию date_trunc() для усечения столбца, чтобы изменить уровень детализации стратегии partitioning. Обратите внимание, что любые другие выражения не поддерживаются.

  • Проверьте, есть ли у вас необходимые привилегии для создания материализованного представления.

    При создании асинхронного материализованного представления вам нужны привилегии SELECT для всех объектов (таблиц, представлений, материализованных представлений), которые запрашиваются. Когда в запросе используются UDF, вам также необходимы привилегии USAGE для функций.

Сбой обновления материализованного представления

Если материализованное представление не удается обновить, то есть состояние задачи обновления не SUCCESS, рассмотрите следующие аспекты:

  • Проверьте, не приняли ли вы неподходящую стратегию обновления.

    По умолчанию материализованное представление обновляется сразу после создания. Однако в версиях v1.5.2 и более ранних материализованные представления, использующие стратегию обновления MANUAL, не обновляются после создания. Вы должны обновить его вручную с помощью REFRESH MATERIALIZED VIEW.

  • Проверьте, не превышает ли задача обновления лимит памяти.

    Обычно это происходит, когда асинхронное материализованное представление включает крупномасштабную агрегацию или join-вычисления, которые исчерпывают ресурсы памяти. Чтобы решить эту проблему, вы можете:

    • Указать стратегию partitioning для материализованного представления для обновления одной partition за раз.
    • Включить функцию Spill to Disk для задачи обновления. Начиная с v1.5.2, Selena поддерживает сброс промежуточных результатов на диск при обновлении материализованного представления. Выполните следующий оператор, чтобы включить Spill to Disk:
    -- Определите свойства при создании материализованного представления.
    CREATE MATERIALIZED VIEW mv1
    REFRESH ASYNC
    PROPERTIES ( 'session.enable_spill'='true' )
    AS <query>;

    -- Добавьте свойства к существующему материализованному представлению.
    ALTER MATERIALIZED VIEW mv2 SET ('session.enable_spill' = 'true');

Тайм-аут обновления материализованного представления

Большие материализованные представления могут не обновиться из-за превышения времени ожидания задачей обновления. Рассмотрите следующие решения для решения этой проблемы:

  • Укажите стратегию partitioning для материализованного представления для достижения детализированного обновления

    Как описано в Create partitioned materialized views, разбивая материализованное представление на partition, вы можете достичь инкрементного создания и обновления, тем самым избегая проблемы чрезмерного потребления ресурсов во время первоначального обновления.

  • Установите более длительное время ожидания

    Время ожидания по умолчанию для задач обновления материализованных представлений составляет 5 минут в версиях ранее v1.5.2 и 1 час в v1.5.2 и более поздних. Если вы сталкиваетесь с исключениями тайм-аута, вы можете настроить период тайм-аута, используя следующий оператор:

    ALTER MATERIALIZED VIEW mv2 SET ('session.insert_timeout' = '4000');
  • Проанализируйте узкие места производительности обновления материализованного представления

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

    • Получите query_id, соответствующий задаче обновления, запросив information_schema.task_runs.
    • Проанализируйте профиль запроса задачи обновления, используя следующие операторы:
      • GET_QUERY_PROFILE: Получите исходный профиль запроса на основе query_id.
      • ANALYZE PROFILE: Проанализируйте профиль запроса на основе фрагментов и отобразите его в виде древовидной структуры.

Состояние материализованного представления неактивно

Если материализованное представление не может перезаписывать запросы или обновляться, и состояние материализованного представления is_active равно false, это может быть результатом изменения схемы базовых таблиц. Чтобы решить эту проблему, вы можете вручную установить состояние материализованного представления как активное, выполнив следующий оператор:

ALTER MATERIALIZED VIEW mv1 ACTIVE;

Если установка состояния материализованного представления как активного не работает, вам необходимо удалить материализованное представление и создать его заново.

Задача обновления материализованного представления использует чрезмерные ресурсы

Если вы обнаружите, что задачи обновления используют чрезмерные системные ресурсы, рассмотрите следующие аспекты:

  • Проверьте, не создали ли вы слишком большое материализованное представление.

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

  • Проверьте, не установили ли вы излишне частый интервал обновления.

    Если вы используете стратегию обновления с фиксированным интервалом, вы можете установить более низкую частоту обновления, чтобы решить проблему. Если задачи обновления запускаются изменениями данных в базовых таблицах, слишком частая загрузка данных также может вызвать эту проблему. Чтобы решить эту проблему, вам необходимо определить подходящую стратегию обновления для вашего материализованного представления.

  • Проверьте, разбито ли материализованное представление на partition.

    Обновление неразбитого материализованного представления может быть дорогостоящим, потому что Selena обновляет все материализованное представление каждый раз. Чтобы решить эту проблему, вам необходимо указать стратегию partitioning для материализованного представления для обновления одной partition за раз.

Чтобы остановить задачу обновления, которая занимает слишком много ресурсов, вы можете:

  • Установить состояние материализованного представления как неактивное, чтобы все его задачи обновления были остановлены:

    ALTER MATERIALIZED VIEW mv1 INACTIVE;
  • Прервать выполняющуюся задачу обновления с помощью CANCEL REFRESH MATERIALIZED VIEW:

    CANCEL REFRESH MATERIALIZED VIEW mv1;

Сбой перезаписи запроса материализованным представлением

Если ваше материализованное представление не может перезаписать соответствующие запросы, рассмотрите следующие аспекты:

  • Диагностируйте сбой перезаписи с помощью TRACE

    Selena предоставляет оператор TRACE для диагностики сбоя перезаписи материализованного представления:

    • TRACE LOGS MV <query>: Доступно в v1.5.2 и более поздних версиях, эта команда анализирует подробный процесс перезаписи и причины сбоя.
    • TRACE REASON MV <query>: Доступно в v1.5.2 и более поздних версиях, эта команда предоставляет краткие причины сбоя перезаписи.
    MySQL > TRACE REASON MV SELECT sum(c1) FROM `glue_ice`.`iceberg_test`.`ice_test3`;
    +----------------------------------------------------------------------------------------------------------------------+
    | Explain String |
    +----------------------------------------------------------------------------------------------------------------------+
    | MV rewrite fail for mv1: Rewrite aggregate rollup sum(1: c1) failed: only column-ref is supported after rewrite |
    | MV rewrite fail for mv1: Rewrite aggregate function failed, cannot get rollup function: sum(1: c1) |
    | MV rewrite fail for mv1: Rewrite rollup aggregate failed: cannot rewrite aggregate functions |
    +----------------------------------------------------------------------------------------------------------------------+
  • Проверьте, совпадают ли материализованное представление и запрос.

    • Selena сопоставляет материализованное представление и запрос с помощью техники сопоставления на основе структуры, а не текстового сопоставления. Поэтому не гарантируется, что запрос может быть перезаписан только потому, что он выглядит похожим на запрос материализованного представления.
    • Материализованные представления могут перезаписывать только запросы типа SPJG (Select/Projection/Join/Aggregation). Запросы, включающие оконные функции, вложенную агрегацию или join плюс агрегацию, не поддерживаются.
    • Материализованные представления не могут перезаписывать запросы, которые включают сложные предикаты Join в Outer Joins. Например, в случаях типа A LEFT JOIN B ON A.dt > '2023-01-01' AND A.id = B.id рекомендуется указать предикат из предложения JOIN ON в предложении WHERE.

    Для получения дополнительной информации об ограничениях перезаписи запросов материализованным представлением см. Query rewrite with materialized views - Limitations.

  • Проверьте, активно ли состояние материализованного представления.

    Selena проверяет статус материализованного представления перед перезаписью запросов. Запросы могут быть перезаписаны только тогда, когда состояние материализованного представления активно. Чтобы решить эту проблему, вы можете вручную установить состояние материализованного представления как активное, выполнив следующий оператор:

    ALTER MATERIALIZED VIEW mv1 ACTIVE;
  • Проверьте, соответствует ли материализованное представление требованиям согласованности данных.

    Selena проверяет согласованность данных в материализованном представлении и в данных базовой таблицы. По умолчанию запросы могут быть перезаписаны только тогда, когда данные в материализованном представлении актуальны. Чтобы решить эту проблему, вы можете:

    • Добавить PROPERTIES('query_rewrite_consistency'='LOOSE') к материализованному представлению, чтобы отключить проверки согласованности.
    • Добавить PROPERTIES('mv_rewrite_staleness_second'='5'), чтобы допустить определенную степень несогласованности данных. Запросы могут быть перезаписаны, если последнее обновление было до этого временного интервала, независимо от того, изменились ли данные в базовых таблицах.
  • Проверьте, не отсутствуют ли в операторе запроса материализованного представления выходные столбцы.

    Для перезаписи запросов диапазона и точечных запросов вы должны указать столбцы, используемые в качестве предикатов фильтрации, в выражении SELECT оператора запроса материализованного представления. Вам необходимо проверить оператор SELECT материализованного представления, чтобы убедиться, что он включает столбцы, на которые ссылаются предложения WHERE и ORDER BY запроса.

Пример 1: Материализованное представление mv1 использует вложенную агрегацию. Таким образом, оно не может быть использовано для перезаписи запросов.

CREATE MATERIALIZED VIEW mv1 REFRESH ASYNC AS
select count(distinct cnt)
from (
select c_city, count(*) cnt
from customer
group by c_city
) t;

Пример 2: Материализованное представление mv2 использует join плюс агрегацию. Таким образом, оно не может быть использовано для перезаписи запросов. Чтобы решить эту проблему, вы можете создать материализованное представление с агрегацией, а затем вложенное материализованное представление с join на основе предыдущего.

CREATE MATERIALIZED VIEW mv2 REFRESH ASYNC AS
select *
from (
select lo_orderkey, lo_custkey, p_partkey, p_name
from lineorder
join part on lo_partkey = p_partkey
) lo
join (
select c_custkey
from customer
group by c_custkey
) cust
on lo.lo_custkey = cust.c_custkey;

Пример 3: Материализованное представление mv3 не может перезаписать запросы в шаблоне SELECT c_city, sum(tax) FROM tbl WHERE dt='2023-01-01' AND c_city = 'xxx', потому что столбец, на который ссылается предикат, отсутствует в выражении SELECT.

CREATE MATERIALIZED VIEW mv3 REFRESH ASYNC AS
SELECT c_city, sum(tax) FROM tbl GROUP BY c_city;

Чтобы решить эту проблему, вы можете создать материализованное представление следующим образом:

CREATE MATERIALIZED VIEW mv3 REFRESH ASYNC AS
SELECT dt, c_city, sum(tax) FROM tbl GROUP BY dt, c_city;

Часто задаваемые вопросы

Какая группа ресурсов контролирует ресурсы для асинхронных материализованных представлений? Как можно настроить её конфигурацию?

Если свойство resource_group не указано при создании асинхронного материализованного представления, система назначает его группе ресурсов по умолчанию default_mv_wg. Её конфигурация по умолчанию:

  • cpu_core_limit: 1
  • mem_limit: 80%
  • concurrency_limit: 0
  • spill_mem_limit_threshold: 80%

Вы можете настроить лимит CPU, лимит памяти, лимит параллелизма и порог сброса через следующие элементы конфигурации BE:

  • default_mv_resource_group_cpu_limit
  • default_mv_resource_group_memory_limit
  • default_mv_resource_group_concurrency_limit
  • default_mv_resource_group_spill_mem_limit_threshold

Вы также можете назначить выделенную группу ресурсов материализованному представлению, указав свойство resource_group.

Пример:

CREATE MATERIALIZED VIEW IF NOT EXISTS mv_test.test_1
PARTITION BY `metric_date`
REFRESH MANUAL
PROPERTIES (
"replicated_storage" = "true",
"partition_refresh_number" = "1",
"force_external_table_query_rewrite" = "CHECKED",
"query_rewrite_consistency" = "LOOSE",
"replication_num" = "1",
"storage_medium" = "HDD",
# highlight-start
"resource_group" = "rg_mv"
# highlight-end
) AS ...

Если асинхронное материализованное представление запланировано обновляться каждую 1 минуту, что произойдет, если обновление займет больше 1 минуты?

Система обрабатывает это автоматически:

  • Если в очереди есть ожидающие задачи, новая запущенная задача объединяется (статус MERGED).
  • Если нет ожидающих задач (только выполняющиеся или успешно завершенные/неудачные задачи), новая запущенная задача ждет, пока текущая выполняющаяся задача не завершится, прежде чем выполняться.

Ограничение: одновременно может выполняться только одна задача обновления на материализованное представление.

После установки auto_refresh_partitions_limit, будет ли система всегда обновлять именно это количество partition?

Нет. Этот параметр представляет верхний лимит. Если система обнаруживает, что изменилось меньше partition базовой таблицы, будут обновлены только эти фактические partition.

Материализованное представление настроено на обновление каждые 5 минут, но в information_schema.task_runs оно, похоже, обновляется каждые 5 секунд. Почему?

Начиная с v1.5.2, значение по умолчанию partition_refresh_number изменилось с -1 на 1, что означает, что каждая операция обновления обрабатывает только одну partition за раз. Если необходимо обновить много partition, система разделяет работу на несколько подзадач, что приводит к более частым записям планирования в task_runs, чем определенный пользователем интервал обновления.

Можно ли вкладывать несколько асинхронных материализованных представлений? Есть ли рекомендации?

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