Как оптимизировать запрос SELECT INTO OUTFILE с помощью LEFT JOIN в MySQL

0

Я выполняю ниже запрос на таблице с 4,45 миллионами строк, и для завершения операции запрос занимает более 15-20 минут. Я попытался изменить Engine от Innodb на MyISAM, но ничего не работает. Я также пытался добавить несколько индексов с обычным и уникальным типом, но все равно занимает одно и то же время.

Вот мой запрос:

SELECT 
a.source, a.destination, a.forward_to, a.start_epoch, a.end_epoch, a.duration, a.billsec, a.outbound_billsec, a.pool_id, a.group_id, a.cost, a.outbound_cost, a.net, a.keep, a.payin, a.payout, a.campaign_id, a.buyer, a.hangup_cause, a.endpoint_disposition, a.uuid, a.agreement, a.agreement_type, a.contract, a.contract_type, a.sip_received_ip,a.termination_ip, 
REPLACE(REPLACE(ifnull(b.line_type,''),'\n',' '),'\r',' ') AS line_type, 
REPLACE(REPLACE(ifnull(b.ocn,''),'\n',' '),'\r',' ') AS ocn, 
REPLACE(REPLACE(ifnull(b.spid_carrier_name,''),'\n',' '),'\r',' ') AS spid_carrier_name 
INTO OUTFILE '/tmp/test-husnain01' 
FIELDS TERMINATED BY ',' FROM inbound_022018 a 
LEFT JOIN wireless_checks b ON (a.uuid = b.uuid) 
WHERE date(a.start_epoch)='2018-02-19' AND 
a.endpoint_disposition='ANSWER' AND 
a.direction='inbound' AND 
a.billed=1;

Ниже приведена моя структура таблицы (inbound_022018):

      CREATE TABLE 'inbound_022018' (
        'id' int(11) NOT NULL AUTO_INCREMENT,
        'source' varchar(20) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
        'destination' varchar(20) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
        'prefix' int(22) NOT NULL,
        'forward_to' varchar(20) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
        'supplier' varchar(32) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
        'agreement' int(11) NOT NULL,
        'agreement_type' varchar(20) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
        'payout' float(11,4) NOT NULL,
        'pool_id' int(11) NOT NULL,
        'group_id' int(11) NOT NULL,
        'campaign_id' bigint(22) NOT NULL,
        'lead' int(1) NOT NULL,
        'cpl' float(11,4) NOT NULL,
        'buyer' varchar(32) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
        'contract' int(11) NOT NULL,
        'contract_type' varchar(20) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
        'payin' float(11,4) NOT NULL,
        'gross' float(11,4) NOT NULL,
        'cost' float(11,4) NOT NULL,
        'outbound_cost' float(11,4) NOT NULL,
        'net' float(11,4) NOT NULL,
        'keep' float(11,4) NOT NULL,
        'direction' varchar(20) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL,
        'session_id' varchar(20) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL,
        'uuid' varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL,
        'sip_from_uri' varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL,
        'sip_received_ip' varchar(20) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
        'domain_name' varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL,
        'sip_req_uri' varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL,
        'endpoint_disposition' varchar(20) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL,
        'hangup_cause' varchar(80) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL,
        'hangup_cause_q850' varchar(80) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL,
        'start_epoch' datetime DEFAULT NULL,
        'answer_epoch' datetime DEFAULT NULL,
        'bridge_epoch' datetime DEFAULT NULL,
        'progress_epoch' datetime DEFAULT NULL,
        'progress_media_epoch' datetime NOT NULL,
        'end_epoch' datetime NOT NULL,
        'digits_dialed' varchar(10) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
        'last_app' varchar(20) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
        'last_arg' varchar(20) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
        'duration' int(11) NOT NULL,
        'g30' int(1) DEFAULT NULL,
        'billsec' int(11) NOT NULL,
        'outbound_duration' int(11) NOT NULL,
        'outbound_billsec' int(11) NOT NULL,
        'progresssec' int(11) NOT NULL,
        'answersec' int(11) NOT NULL,
        'waitsec' int(11) NOT NULL,
        'progress_mediasec' int(11) NOT NULL,
        'flow_billsec' int(11) NOT NULL,
        'sip_hangup_disposition' int(11) NOT NULL,
        'callForwarded' varchar(10) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
        'forwardUuid' varchar(40) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
        'call_type' enum('s','v') CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT 's',
        'billed' int(1) NOT NULL,
        'uc' int(1) NOT NULL,
        'suc' int(1) NOT NULL,
        'callinfo' varchar(250) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
        'termination_ip' varchar(20) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
        'switchname' varchar(10) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
        'org_charges' float(11,4) NOT NULL,
        'call_summary' text,
        PRIMARY KEY ('id'),
        UNIQUE KEY 'index_inbound_0717' ('id') USING BTREE,
        UNIQUE KEY 'index_uuid' ('uuid') USING BTREE,
        UNIQUE KEY 'index_all' ('id','campaign_id','session_id','uuid') USING BTREE,
        KEY 'index_source' ('source') USING BTREE,
        KEY 'index_destination' ('destination') USING BTREE,
        KEY 'index_endpoint' ('endpoint_disposition') USING BTREE,
        KEY 'index_build' ('billed') USING BTREE,
        KEY 'index_campainid' ('campaign_id') USING BTREE
      ) ENGINE=MyISAM AUTO_INCREMENT=4457485 DEFAULT CHARSET=latin1

Вот вторая таблица (wireless_checks):

         CREATE TABLE 'wireless_checks' (
        'id' int(22) NOT NULL AUTO_INCREMENT,
        'date' varchar(10) NOT NULL,
        'uuid' varchar(100) NOT NULL,
        'tn' varchar(11) NOT NULL,
        'lrn' varchar(11) NOT NULL,
        'ported_status' varchar(2) NOT NULL,
        'ported_date' varchar(11) NOT NULL,
        'ocn' varchar(10) NOT NULL,
        'line_type' int(1) NOT NULL,
        'spid' varchar(10) NOT NULL,
        'spid_carrier_name' varchar(100) NOT NULL,
        'spid_carrier_type' varchar(10) NOT NULL,
        'altspid_carrier_name' varchar(10) NOT NULL,
        'altspid_carrier_type' varchar(10) NOT NULL,
        PRIMARY KEY ('id'),
        UNIQUE KEY 'index_uuid' ('uuid') USING BTREE
      ) ENGINE=MyISAM AUTO_INCREMENT=36175 DEFAULT CHARSET=latin1

Сообщите мне, как я могу оптимизировать этот запрос, чтобы сократить время выполнения. Я также открыт для обхода проблемы, если есть какой-либо другой подход, чтобы сделать это. Любая помощь будет оценена.

Спасибо

Husnain

  • 0
    Подумайте об изучении и использовании EXPLAIN .
Теги:
myisam
innodb
into-outfile

2 ответа

0

SELECT INTO OUTFILE не является проблемой. Многое другое замедляет запрос.

Вот фрагменты, которые мне нужно обсудить:

    FROM  inbound_022018 a
    LEFT JOIN  wireless_checks b  ON (a.uuid = b.uuid)
    WHERE  date(a.start_epoch)='2018-02-19'
      AND  a.endpoint_disposition='ANSWER'
      AND  a.direction='inbound'
      AND  a.billed=1;

    'uuid' varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL,

    'uuid' varchar(100) NOT NULL ... DEFAULT CHARSET=latin1

    float(11,4)

    'date' varchar(10) NOT NULL, ...
    'ported_date' varchar(11) NOT NULL,

    PRIMARY KEY ('id'),
    UNIQUE KEY 'index_inbound_0717' ('id') USING BTREE,

    PRIMARY KEY ('id'), ...
    UNIQUE KEY 'index_all' ('id','campaign_id','session_id','uuid') USING BTREE,

Много проблем:

  • UUID носят "случайный" характер. Насколько велики ваши таблицы? Если они больше, чем кэшируются в ОЗУ, запрос обречен на медленную работу.
  • При сравнении двух строк (a.uuid = b.uuid) индексы не могут использоваться, если кодировка или сортировка различны. Исправьте это.
  • Еще меньшим было бы преобразование из строк в BINARY(16). (Код доступен в другом месте).
  • UUID, если у вас нет чего-то особенного, может быть CHAR (26) CHARSET ascii. Это очищает несколько вещей.
  • Таблица необходим композитный a INDEX(billed, direction, endpoint_disposition, start_epoch), чтобы сделать WHERE более эффективным. Первые 3 столбца могут быть в любом порядке.
  • Измените дату, как указано ниже.
  • PRIMARY KEY - UNIQUE ключ; удалите последний.
  • FLOAT(m,n) - бесполезная конструкция, потому что она включает в себя два закругления. Для денежных значений используйте DECIMAL(m,n); для "научных" значений используйте FLOAT без (m,n).
  • Почти никогда не бывает, чтобы вторичный ключ начинался со всех столбцов ПК. (Хорошо, MyISAM может принести пользу, но InnoDB редко делает.)
  • Если вам не нужно b.id для чего угодно, избавитесь от него и продвигайте uuid чтобы быть ПК. Это ускорит JOIN для InnoDB.
  • Если у вас нет веских оснований, не ставьте даты в VARCHAR.
  • Не используйте MyISAM; исправить проблемы, которые я обсуждал здесь. Затем вернитесь для дальнейшего обсуждения, если это необходимо.

Когда столбец "скрыт" внутри функции (например, DATE()), индексирование столбца не помогает. Изменить на

WHERE  a.start_epoch >= '2018-02-19'
  AND  a.start_epoch  < '2018-02-19' + INTERVAL 1 DAY

С этим изменением 4-я колонка в моем предлагаемом INDEX будет использоваться.

0

Один совет, который должен иметь значение, заключается в том, что вместо того, чтобы делать

WHERE date(a.start_epoch)='2018-02-19'

вам следует подумать об этом заранее, а затем использовать реальное значение, то есть 1518998400

Причина, по которой это красный флаг, заключается в том, что, поместив функцию слева от сравнения, вы вынуждаете базу данных выполнять полное сканирование таблицы, выполняя эту функцию во всех строках 4.45m, просто для обработки WHERE. Если вместо этого вы сравниваете сам столбец с реальным значением, не используя функцию DATE, тогда MySQL может оптимизировать запрос гораздо эффективнее и будет использовать индекс в a.start_epoch если он доступен.

Чтобы создать этот индекс, просто выполните

CREATE INDEX epoch_idx on inbound_022018(start_epoch)

В более широком смысле вы должны создавать индексы против столбцов, которые имеют большой разброс значений (не только 1 или 2 возможности), а многоколоночные индексы могут помочь в оптимизации сложных запросов.

Помещение EXPLAIN перед запросом и просмотр результатов для особо больших чисел строк - это хороший способ определить, где стоимость находится в запросе. Часто эффективная индексация решит проблему.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню