Оптимизация запроса с огромным объемом данных

#sql-server #tsql

Вопрос:

Как я могу оптимизировать запрос. Я просмотрел план выполнения и создал весь индекс. Каждая таблица содержит огромные данные. И это время выполнения запроса очень велико. Посмотрев на запрос, не могли бы вы, пожалуйста, подсказать, где я могу оптимизировать больше.

Если я приведу небольшую предысторию запроса, структура будет выглядеть так:

  1. Существует множество компаний
  2. В каждой компании может быть несколько менеджеров
  3. Данные представлены в формате разбиения на страницы
  4. Фильтр на #parent_manager, поэтому другая временная таблица создала parent_manager_filter только для использования в целях фильтрации, поскольку #parent_manager имеет имя в формате»,», разделенном
 CREATE TABLE #parent_manager 
(
    cid NUMERIC(18) PRIMARY KEY, 
    name NVARCHAR(MAX), 
    code NVARCHAR(MAX)
);

CREATE INDEX cte_parent_manager ON #parent_manager(cid);

CREATE TABLE #parent_manager_filter 
(
    cid NUMERIC(18), 
    name NVARCHAR(1000), 
    code NVARCHAR(1000)
);

CREATE INDEX cte_parent_manager_filter_idx ON #parent_manager_filter(cid);

INSERT INTO #parent_manager 
    SELECT DISTINCT
        mgrc.cid,
        name = CAST (STUFF ((SELECT ', '   CAST(c.company_name AS varchar(2000)) 
                             FROM manager_company mc 
                             INNER JOIN company c ON (mc.mgr_cid = c.cid ) 
                             WHERE mc.cid = mgrc.cid 
                               AND c.company_name IS NOT NULL
                             FOR XML PATH ('')), 1, 1, '') AS VARCHAR(2000)),
        code = CAST (STUFF ((SELECT ', '   CAST(c.code AS varchar(2000)) 
                             FROM manager_company mc 
                             INNER JOIN company c ON (mc.mgr_cid = c.cid ) 
                             WHERE mc.cid = mgrc.cid 
                               AND c.company_name IS NOT NULL
                             FOR XML PATH ('')), 1, 1, '') AS VARCHAR(2000)) 
    FROM
        manager_company mgrc 
    INNER JOIN 
        company c ON (mgrc.mgr_cid = c.cid ) 
    JOIN
        handler h ON (c.handlerId = h.handlerid ) 
    WHERE
        h.handlerid = 5800657002370

INSERT INTO #parent_manager_filter 
    SELECT DISTINCT 
        mc.cid,
        c.company_name as name,
        c.code as code 
    FROM
        manager_company mc 
    INNER JOIN
        company c ON (mc.mgr_cid = c.cid ) 
    JOIN
        handler h ON (h.handlerid = c.handlerid) 
    WHERE
        h.handlerid = 5800657002370 ;

WITH company AS
(
    SELECT DISTINCT
        c.cid AS cid,
        parentManager.name AS MANAGER_NAME,
        parentManager.code AS code 
    FROM
        company c 
    LEFT JOIN
        #parent_manager parentManager ON (parentManager.cid = c.cid) 
    LEFT JOIN
        # parent_manager_filter parentManagerFilter ON (parentManagerFilter.cid = c.cid) 
    WHERE
        parentManagerFilter.name IN (:managerList)
),
total_rows AS
(
    SELECT 
        COUNT(*) OVER () AS TOTALCOUNT,
        ROW_NUMBER() OVER (ORDER BY company_name ASC) AS rnum,
        grid.* 
    FROM
        company grid 
)
SELECT * 
FROM total_rows rnum 
WHERE rnum >= 1 
  AND rnum <= 10 

DROP TABLE #parent_manager;
DROP TABLE #parent_manager_filter;
 

Комментарии:

1. Я бы рекомендовал использовать лучшие измерения, чем «огромные данные» и «время выполнения очень велико» или «большая компания», потому что это настолько неясно, что никто не будет знать, с чего начать. Укажите точные измерения, продолжительность, структуры таблиц и индексирования, а также план запроса.

2. Почему вы заявляете varchar(max) , какие у вас данные varchar(2000) , и я бы задался вопросом, нужно ли вам это тоже numeric(18) — так что это bigint тогда? Тебе это нужно ? Используйте соответствующие типы данных — для миллионов строк это определенно поможет.

3. Пожалуйста, смотрите раздел вставка плана , чтобы узнать, как включить план выполнения в свой вопрос. Где находится DDL handler и его индекс(индексы)?

Ответ №1:

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

 INSERT INTO #parent_manager_filter ...
CREATE CLUSTERED INDEX cte_parent_manager_filter On #parent_manager_filter(cid);
 

Комментарии:

1. Да, индекс был создан, пропустив эту часть.

2. @Techie321 Улучшилась ли скорость запроса?

3. Это уже было там, я пропустил, чтобы упомянуть об этом здесь.

4. Вы пробовали вынимать подзапросы внутри выборок (в основном материалы)? Сокращает ли это время запроса?

5. Кроме того, почему вы этим занимаетесь, вы можете захотеть создать некластеризованный индекс для #parent_manager.code и #parent_manager_filter.code. Это может повредить чему угодно, и вы можете сравнить планы запросов.