Улучшение производительности запросов - PullRequest
0 голосов
/ 15 февраля 2012

У меня есть такой запрос (сгенерированный Hibernate - отредактирован для большей ясности - ниже вы найдете полный запрос):

select 
visitgroup0_.VISIT_ID as col_0_0_ ... 
from 
ADM_VISIT_GROUP visitgroup0_, 
ADM_CONTACT_OWNER contactown1_ 
where 
visitgroup0_.TIME>'2012-02-14 02:59:24' and 
visitgroup0_.VENDOR_ID='***' and 
visitgroup0_.CONTACT_STATE='PROSPECT' and 
contactown1_.CONTACT_ID=visitgroup0_.CONTACT_ID and 
contactown1_.OWNER_ID='***' order by visitgroup0_.TIME desc limit 30;

Вкратце, я регистрирую посещения клиентов на нашем сайте, каждому клиенту назначен владелец - торговый представитель. Мне нужно показать владельцу посещения его контактов.

Посещения хранятся в таблице ADM_VISIT_GROUP -> 200 000 строк, посещение имеет столбец contact_id, указывающий на ADM_CONTACT. Контакты хранятся в таблице ADM_CONTACT - около 500 000 строк. Право собственности на контакт сохраняется в таблице ADM_CONTACT_OWNER - количество строк примерно такое же, как в ADM_CONTACT.

Объяснить показывает:

+----+-------------+--------------+--------+----------------------------------------------------------------------------------------------------------------------------------+----------------------+---------+------------------------------------------------+-------+--------------------------+
| id | select_type | table        | type   | possible_keys                                                                                                                    | key                  | key_len | ref                                            | rows  | Extra                    |
+----+-------------+--------------+--------+----------------------------------------------------------------------------------------------------------------------------------+----------------------+---------+------------------------------------------------+-------+--------------------------+
|  1 | SIMPLE      | visitgroup0_ | range  | FK_VISIT_GROUP_VENDOR_ID,IDX_VISIT_GROUP_VENDOR_ID_CONTACT_ID,IDX_VISIT_GROUP_TIME,IDX_VISIT_GROUP_CONTACT_ID                    | IDX_VISIT_GROUP_TIME | 9       | NULL                                           | 19640 | Using where              |
|  1 | SIMPLE      | contactown1_ | eq_ref | CONTACT_ID,FK_CONTACT_OWNER_CONTACT_ID,FK_CONTACT_OWNER_OWNER_ID,IDX_CONTACT_OWNER_CONTACT_OWNER,IDX_CONTACT_OWNER_OWNER_DELETED | CONTACT_ID           | 1534    | salesmanago_main.visitgroup0_.CONTACT_ID,const |     1 | Using where; Using index |
+----+-------------+--------------+--------+----------------------------------------------------------------------------------------------------------------------------------+----------------------+---------+------------------------------------------------+-------+--------------------------+

Таблица ADM_VISIT_GROUP создана с использованием:

CREATE TABLE `ADM_VISIT_GROUP` (
  `ID` char(128) COLLATE utf8_polish_ci NOT NULL,
  `UUID` varchar(255) COLLATE utf8_polish_ci DEFAULT NULL,
  `CONTACT_STATE` varchar(255) COLLATE utf8_polish_ci DEFAULT NULL,
  `VISIT_ID` varchar(255) COLLATE utf8_polish_ci DEFAULT NULL,
  `HOST` varchar(255) COLLATE utf8_polish_ci DEFAULT NULL,
  `IP` varchar(255) COLLATE utf8_polish_ci DEFAULT NULL,
  `LOCATION` varchar(255) COLLATE utf8_polish_ci DEFAULT NULL,
  `URI` varchar(255) COLLATE utf8_polish_ci DEFAULT NULL,
  `TIME` datetime DEFAULT NULL,
  `CONVERSATION` varchar(255) COLLATE utf8_polish_ci DEFAULT NULL,
  `DURATION` bigint(20) DEFAULT NULL,
  `VISIT_SOURCE` varchar(255) COLLATE utf8_polish_ci NOT NULL,
  `VISIT_SOURCE_HOST` varchar(255) COLLATE utf8_polish_ci DEFAULT NULL,
  `VISIT_SOURCE_KEYWORDS` varchar(1024) COLLATE utf8_polish_ci DEFAULT NULL,
  `VISIT_SOURCE_DETAILS` varchar(255) COLLATE utf8_polish_ci DEFAULT NULL,
  `VISIT_SCORE` bigint(20) DEFAULT NULL,
  `CLIENT` varchar(255) COLLATE utf8_polish_ci DEFAULT NULL,
  `EMAIL` varchar(255) COLLATE utf8_polish_ci DEFAULT NULL,
  `CONTACT_ID` varchar(255) COLLATE utf8_polish_ci DEFAULT NULL,
  `CONVERSATION_ID` varchar(255) COLLATE utf8_polish_ci DEFAULT NULL,
  `IP_ORGANIZATION` varchar(255) COLLATE utf8_polish_ci DEFAULT NULL,
  `ISP_ONLY` tinyint(1) DEFAULT NULL,
  `VENDOR_ID` varchar(255) COLLATE utf8_polish_ci NOT NULL,
  PRIMARY KEY (`ID`),
  KEY `FK_VISIT_GROUP_VENDOR_ID` (`VENDOR_ID`),
  KEY `IDX_VISIT_GROUP_VENDOR_ID_CONTACT_ID` (`VENDOR_ID`,`CONTACT_ID`),
  KEY `IDX_VISIT_GROUP_ISP_ONLY_VENDOR_ID_CONTACT_ID` (`ISP_ONLY`,`VENDOR_ID`,`CONTACT_ID`),
  KEY `IDX_VISIT_GROUP_TIME` (`TIME`),
  KEY `IDX_VISIT_GROUP_EMAIL` (`EMAIL`),
  KEY `IDX_VISIT_GROUP_CONTACT_ID` (`CONTACT_ID`),
  CONSTRAINT `FK_VISIT_GROUP_VENDOR_ID` FOREIGN KEY (`VENDOR_ID`) REFERENCES `ADM_VENDOR` (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci

Таблица ADM_CONTACT_OWNER:

CREATE TABLE `ADM_CONTACT_OWNER` (
  `ID` char(128) COLLATE utf8_polish_ci NOT NULL,
  `VERSION` int(11) NOT NULL,
  `CONTACT_ID` varchar(255) COLLATE utf8_polish_ci NOT NULL,
  `OWNER_ID` varchar(255) COLLATE utf8_polish_ci NOT NULL,
  `CREATED_ON` datetime NOT NULL,
  `OWNERSHIP_RIGHTS` varchar(255) COLLATE utf8_polish_ci NOT NULL,
  `GRANTED_BY_ID` varchar(255) COLLATE utf8_polish_ci NOT NULL,
  `MODIFIED_ON` datetime NOT NULL,
  `DELETED` tinyint(1) NOT NULL,
  PRIMARY KEY (`ID`),
  UNIQUE KEY `CONTACT_ID` (`CONTACT_ID`,`OWNER_ID`),
  KEY `FK_CONTACT_OWNER_GRANTED_BY_ID` (`GRANTED_BY_ID`),
  KEY `FK_CONTACT_OWNER_CONTACT_ID` (`CONTACT_ID`),
  KEY `FK_CONTACT_OWNER_OWNER_ID` (`OWNER_ID`),
  KEY `IDX_CONTACT_OWNER_CONTACT_OWNER` (`CONTACT_ID`,`OWNER_ID`),
  KEY `IDX_CONTACT_OWNER_OWNER_DELETED` (`OWNER_ID`,`DELETED`),
  CONSTRAINT `FK_CONTACT_OWNER_CONTACT_ID` FOREIGN KEY (`CONTACT_ID`) REFERENCES `ADM_CONTACT` (`ID`),
  CONSTRAINT `FK_CONTACT_OWNER_GRANTED_BY_ID` FOREIGN KEY (`GRANTED_BY_ID`) REFERENCES `ADM_USER_ACCOUNT` (`ID`),
  CONSTRAINT `FK_CONTACT_OWNER_OWNER_ID` FOREIGN KEY (`OWNER_ID`) REFERENCES `ADM_USER_ACCOUNT` (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci

Полный запрос:

    select 
visitgroup0_.VISIT_ID as col_0_0_, 
visitgroup0_.DURATION as col_1_0_, 
visitgroup0_.TIME as col_2_0_, 
visitgroup0_.VISIT_SOURCE as col_3_0_, 
visitgroup0_.VISIT_SOURCE_HOST as col_4_0_, 
visitgroup0_.VISIT_SOURCE_KEYWORDS as col_5_0_, 
visitgroup0_.EMAIL as col_6_0_, 
visitgroup0_.IP_ORGANIZATION as col_7_0_, 
visitgroup0_.CLIENT as col_8_0_, 
visitgroup0_.HOST as col_9_0_, 
visitgroup0_.IP as col_10_0_, 
visitgroup0_.LOCATION as col_11_0_, 
visitgroup0_.URI as col_12_0_, 
visitgroup0_.UUID as col_13_0_, 
visitgroup0_.VISIT_SCORE as col_14_0_, 
visitgroup0_.CONVERSATION as col_15_0_, 
visitgroup0_.CONTACT_ID as col_16_0_, 
visitgroup0_.CONVERSATION_ID as col_17_0_ 
from 
ADM_VISIT_GROUP visitgroup0_, 
ADM_CONTACT_OWNER contactown1_ 
where 
visitgroup0_.TIME>'2012-02-14 02:59:24' and 
visitgroup0_.VENDOR_ID='3739d7a7-2e8f-4409-bd2d-2b505b5e7749' and 
visitgroup0_.CONTACT_STATE='PROSPECT' and 
contactown1_.CONTACT_ID=visitgroup0_.CONTACT_ID and 
contactown1_.OWNER_ID='3f440a3e-a55e-44f5-ac75-d30bd27f4f97' 
order by visitgroup0_.TIME desc limit 30;

Может кто-нибудь помочь мне улучшить скорость этого запроса?

Ответы [ 2 ]

1 голос
/ 15 февраля 2012

Необходимо вручную отфильтровать множество строк, поскольку mysql может использовать только индекс по ВРЕМЕНИ (IDX_VISIT_GROUP_TIME)

Поскольку MySQL может использовать только один индекс для таблицы в запросе, попробуйте создать комбинированный индекс для:

VENDOR_ID
CONTACT_STATE
CONTACT_ID
TIME

Порядок столбцов важен в индексах! Индекс может использоваться только от первого предложения до последнего, если все предложения находятся в запросе. И использование> или чего-то подобного, скорее всего, сделает остальную часть индекса непригодной для использования. Вот почему ВРЕМЯ является последним в индексе.

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

0 голосов
/ 15 февраля 2012

Я бы:

  • Измените тип данных OWNER_ID, VENDOR_ID и CONTACT_ID с VARCHAR на UNSIGNED INTEGER или любой другой числовой тип
  • Используйте JOIN между ADM_VISIT_GROUP и ADM_CONTACT_OWNER
  • изменить CONTACT_STATE на внешний ключ таблицы STATE или использовать числовое поле
  • улучшение INDEX создания
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...