Я выполняю ниже запрос на таблице с 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
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,
Много проблем:
a.uuid = b.uuid
) индексы не могут использоваться, если кодировка или сортировка различны. Исправьте это.BINARY(16)
. (Код доступен в другом месте).a
INDEX(billed, direction, endpoint_disposition, start_epoch)
, чтобы сделать WHERE
более эффективным. Первые 3 столбца могут быть в любом порядке.PRIMARY KEY
- UNIQUE
ключ; удалите последний.FLOAT(m,n)
- бесполезная конструкция, потому что она включает в себя два закругления. Для денежных значений используйте DECIMAL(m,n)
; для "научных" значений используйте FLOAT
без (m,n)
.b.id
для чего угодно, избавитесь от него и продвигайте uuid
чтобы быть ПК. Это ускорит JOIN
для InnoDB.VARCHAR
. Когда столбец "скрыт" внутри функции (например, DATE()
), индексирование столбца не помогает. Изменить на
WHERE a.start_epoch >= '2018-02-19'
AND a.start_epoch < '2018-02-19' + INTERVAL 1 DAY
С этим изменением 4-я колонка в моем предлагаемом INDEX
будет использоваться.
Один совет, который должен иметь значение, заключается в том, что вместо того, чтобы делать
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
перед запросом и просмотр результатов для особо больших чисел строк - это хороший способ определить, где стоимость находится в запросе. Часто эффективная индексация решит проблему.
EXPLAIN
.