Нужно настроить запрос MySQL - PullRequest
0 голосов
/ 02 января 2019

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

Создание оператора таблицы и объяснение плана были представлены ниже.

UPDATE TEMP_MESSAGE_SPLIT t1 , TEMP_MESSAGE_SPLIT t2
    SET t1.STATUS = 'D'
    WHERE
    (t1.temp_message_split_key < t2.temp_message_split_key AND t1.DH_MEMBER_ID = t2.DH_MEMBER_ID)
    AND  nullif(t1.dh_member_id,'') IS NOT NULL;

Вот таблица создания DDL

CREATE TABLE
temp_message_split
(
    FIRST_NAME VARCHAR(20),
    LAST_NAME VARCHAR(30),
    DOB VARCHAR(10),
    EMPLOYEE_ID VARCHAR(20),
    CES_CUST_NUM VARCHAR(7),
    MED_POLICY_NUM VARCHAR(20),
    EMAIL_ADDR VARCHAR(50),
    DH_MEMBER_ID VARCHAR(9),
    ALT_ID VARCHAR(20),
    DRSN VARCHAR(2),
    SSN VARCHAR(9),
    EPIPHANY_MEMBER_ID VARCHAR(18),
    PORTAL_ADDRESS VARCHAR(30),
    STATEMENT_VENDOR VARCHAR(20),
    CONTENT_KEY VARCHAR(18),
    EPIPHANY_COMMUNICATION_ID VARCHAR(200),
    PRIORITY VARCHAR(4),
    DAYS_UNTIL_EXPIRED VARCHAR(4),
    CONTENT_DTL_KEY VARCHAR(18),
    STATUS VARCHAR(1),
    ACTIVATION_MEMBER_KEY bigint,
    MESSAGE_BOARD_KEY bigint,
    PORTAL_STATEMENT_LOC_KEY bigint,
    temp_message_split_KEY bigint NOT NULL AUTO_INCREMENT,
    PRIMARY KEY (temp_message_split_KEY),
    INDEX EPIPHANY_COMMUNICATION_ID_IDX (EPIPHANY_COMMUNICATION_ID),
    INDEX TEMP_MESSAGE_SPLIT_IDX2 (ALT_ID),
    INDEX TEMP_MESSAGE_SPLIT_IDX3 (DRSN),
    INDEX TEMP_MESSAGE_SPLIT_IDX4 (ALT_ID, DRSN),
    INDEX TEMP_MESSAGE_SPLIT_IDX1 (DH_MEMBER_ID)
)
ENGINE=InnoDB DEFAULT CHARSET=utf8;

Вот ее план объяснения:

+----+-------------+-------+------------+-------+---------------------------------+-------------------------+---------+------+---------+----------+------------------------------------------------+
| id | select_type | table | partitions | type  | possible_keys                   | key                     | key_len | ref  | rows    | filtered | Extra                                          |
+----+-------------+-------+------------+-------+---------------------------------+-------------------------+---------+------+---------+----------+------------------------------------------------+
|  1 | SIMPLE      | t2    | NULL       | index | PRIMARY,TEMP_MESSAGE_SPLIT_IDX1 | TEMP_MESSAGE_SPLIT_IDX1 | 30      | NULL | 1619639 |   100.00 | Using index                                    |
|  1 | UPDATE      | t1    | NULL       | ALL   | PRIMARY,TEMP_MESSAGE_SPLIT_IDX1 | NULL                    | NULL    | NULL | 1619639 |    33.33 | Range checked for each record (index map: 0x5) |
+----+-------------+-------+------------+-------+---------------------------------+-------------------------+---------+------+---------+----------+------------------------------------------------+
2 rows in set (0.00 sec)

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

Ответы [ 2 ]

0 голосов
/ 02 января 2019

Спасибо, Гордан, за ваш последний комментарий. Я обновил запрос на основе этого, и теперь он завершается в течение нескольких секунд. Вот мой новый запрос:

UPDATE TEMP_MESSAGE_SPLIT t1 , TEMP_MESSAGE_SPLIT t2
    SET t1.STATUS = 'D'
    WHERE
    (t1.temp_message_split_key < t2.temp_message_split_key AND t1.DH_MEMBER_ID = t2.DH_MEMBER_ID)
    AND t1.DH_MEMBER_ID <> ''

Не могли бы вы помочь мне понять, как такие незначительные изменения в запросе вызвали такую ​​огромную разницу в производительности запросов.

0 голосов
/ 02 января 2019

Мое лучшее предположение заключается в том, что вы хотите установить статус D для всех, кроме самого высокого значения temp_message_split_key для каждого DH_MEMBER_ID.

Лучшее решение - NOT EXISTS, но MySQL не поддерживает NOT EXISTS для той же таблицы в запросе UPDATE.

Итак, другой метод использует GROUP BY:

UPDATE TEMP_MESSAGE_SPLIT t1 JOIN
       (SELECT t2.DH_MEMBER_ID, MAX(t2.temp_message_split_key) as max_temp_message_split_key
        FROM TEMP_MESSAGE_SPLIT t2
        GROUP BY t2.DH_MEMBER_ID
       ) t2
       ON t1.DH_MEMBER_ID = t2.DH_MEMBER_ID AND
          t1.temp_message_split_key < t2.max_temp_message_split_key
    SET t1.STATUS = 'D';

Индекс на (dh_member_id, temp_message_split_key) может помочь производительности.

Это все еще займет много времени, потому что вы (предположительно) обновляете много строк. Если возможно, то, вероятно, проще просто создать новую таблицу с нужными значениями. Это будет намного быстрее (из-за регистрации и блокировки).

Возможно, NULLIF() ничего не делает, но он оказывает минимальное влияние на производительность вашего запроса. Было бы лучше написать как t1.dh_member_id <> ''.

...