I have such query (generated by Hibernate – edited for more clarity – below you will find full query):
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;
Briefly, I am logging customers visits on our website, each customer has assigned owner – sales rep. I need to show to owner visits of his contacts.
Visits are stored in ADM_VISIT_GROUP table – > 200 000 rows, visit has contact_id column pointing to ADM_CONTACT.
Contacts are stored in ADM_CONTACT table – around 500 000 rows.
Ownership of contact is stored in ADM_CONTACT_OWNER table – more or less same amount of rows as in ADM_CONTACT.
Explain shows:
+----+-------------+--------------+--------+----------------------------------------------------------------------------------------------------------------------------------+----------------------+---------+------------------------------------------------+-------+--------------------------+
| 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 table created using:
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
Table 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
Full query:
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;
Can anyone help me with improving this query speed?
It has to manually filter out a lot of rows because of mysql only being able to use an index on TIME (IDX_VISIT_GROUP_TIME)
Because MySQL can only use a single index per table in a query, try making a combined index on:
The order of the columns is important in indexes! An index can only be used from the first clause to the last, if all clauses are in the query. And using > or something like that will most probably make the rest of the index not usable. That is why TIME is last in the index.
But of a certain column does not appear in your where clause it cannot reach the part of the index for the TIME column and the index is a lot less effective. That’s why in such a case you’ll want to create a seperate index with those columns.