I have a sql statement that looks like this:
SELECT colID
FROM tableName
WHERE ColDateStart <='$lowerDate'
AND ColDateStart>='$upperDate'
AND ColVcamID='$id1'
AND ColVlviID='$id2'
AND ColSomeID='$id3';
All the columns in the WHERE statment are indexed columns.
When I run this it takes over a second. However when I run this without other Id3, the performance is considerably improved (0.03 seconds).
When I run explain, with otherId3, it uses an index merge using otherId1 and otherId3. However when I remove the otherId3, it uses the single index of otherId2.
Why does adding otherId3 make an impact on the performance?
Table Structure:
+----------------------+-------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+-------------+------+-----+---------------------+----------------+
| ColID | int(11) | NO | PRI | NULL | auto_increment |
| ColCustID | int(11) | NO | MUL | 0 | |
| ColCarrID | int(11) | NO | MUL | NULL | |
| ColTariID | int(11) | NO | MUL | 0 | |
| ColCarrierRef | varchar(30) | NO | MUL | | |
| ColNumbID | int(11) | NO | MUL | 0 | |
| ColVlviID | int(11) | NO | MUL | NULL | |
| ColVcamID | int(11) | NO | MUL | NULL | |
| ColSomeID | int(11) | NO | MUL | NULL | |
| ColVlnsID | int(11) | NO | MUL | NULL | |
| ColNGNumber | varchar(12) | NO | | | |
| ColOrigNumber | varchar(16) | NO | MUL | NULL | |
| ColCLIRestrictedFlag | int(2) | NO | | NULL | |
| ColOrigLocality | varchar(11) | NO | MUL | | |
| ColOrigAreaCode | varchar(11) | NO | MUL | | |
| ColTermNumber | varchar(16) | NO | MUL | NULL | |
| ColBatchNumber | varchar(10) | NO | | | |
| ColDateStart | date | NO | MUL | 0000-00-00 | |
| ColDateClear | date | NO | | 0000-00-00 | |
| ColTimeStart | time | NO | | 00:00:00 | |
| ColTimeClear | time | NO | | 00:00:00 | |
| ColCallLength | time | NO | | 00:00:00 | |
| ColRingLength | time | NO | | 00:00:00 | |
| ColEffectiveFlag | smallint(1) | NO | MUL | NULL | |
| ColUnansweredFlag | smallint(1) | NO | MUL | NULL | |
| ColEngagedFlag | smallint(1) | NO | | NULL | |
| ColRecID | int(11) | NO | MUL | NULL | |
| ColCreatedUserID | int(11) | NO | | 0 | |
| ColCreatedDatetime | datetime | NO | MUL | 0000-00-00 00:00:00 | |
| ColDirection | int(1) | NO | MUL | NULL | |
+----------------------+-------------+------+-----+---------------------+----------------+
Indexes
+-------+------------+-------------------------------+--------------+---------------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-------+------------+-------------------------------+--------------+---------------------+-----------+-------------+----------+--------+------+------------+---------+
| tableName | 0 | PRIMARY | 1 | ColID | A | 18031283 | NULL | NULL | | BTREE | |
| tableName | 1 | idx_ColCustID | 1 | ColCustID | A | 1339 | NULL | NULL | | BTREE | |
| tableName | 1 | idx_ColNumbID | 1 | ColNumbID | A | 24366 | NULL | NULL | | BTREE | |
| tableName | 1 | idx_colOrigNumber | 1 | colOrigNumber | A | 4507820 | NULL | NULL | | BTREE | |
| tableName | 1 | idx_colOrigLocality | 1 | colOrigLocality | A | 36873 | NULL | NULL | | BTREE | |
| tableName | 1 | idx_colOrigAreaCode | 1 | colOrigAreaCode | A | 696 | NULL | NULL | | BTREE | |
| tableName | 1 | idx_colTermNumber | 1 | colTermNumber | A | 137643 | NULL | NULL | | BTREE | |
| tableName | 1 | idx_colDateStart | 1 | colDateStart | A | 3639 | NULL | NULL | | BTREE | |
| tableName | 1 | idx_colEffectiveFlag | 1 | colEffectiveFlag | A | 2 | NULL | NULL | | BTREE | |
| tableName | 1 | idx_colUnansweredFlag | 1 | colUnansweredFlag | A | 2 | NULL | NULL | | BTREE | |
| tableName | 1 | idx_colEngagedFlag | 1 | colUnansweredFlag | A | 2 | NULL | NULL | | BTREE | |
| tableName | 1 | idx_colTariID | 1 | colTariID | A | 91 | NULL | NULL | | BTREE | |
| tableName | 1 | idx_CustID_DateStart | 1 | colCustID | A | 1339 | NULL | NULL | | BTREE | |
| tableName | 1 | idx_CustID_DateStart | 2 | colDateStart | A | 693510 | NULL | NULL | | BTREE | |
| tableName | 1 | idx_NumbID_DateStart | 1 | colNumbID | A | 24366 | NULL | NULL | | BTREE | |
| tableName | 1 | idx_NumbID_DateStart | 2 | colDateStart | A | 4507820 | NULL | NULL | | BTREE | |
| tableName | 1 | idx_colRecID | 1 | colRecID | A | 214658 | NULL | NULL | | BTREE | |
| tableName | 1 | idx_colCarrierRef | 1 | colCarrierRef | A | 6010427 | NULL | NULL | | BTREE | |
| tableName | 1 | idx_colCustID_colTermNumber | 1 | colCustID | A | 1339 | NULL | NULL | | BTREE | |
| tableName | 1 | idx_colCustID_colTermNumber | 2 | colTermNumber | A | 143105 | NULL | NULL | | BTREE | |
| tableName | 1 | idx_colCreatedDatetime | 1 | colCreatedDatetime | A | 474507 | NULL | NULL | | BTREE | |
| tableName | 1 | idx_colDirection | 1 | colDirection | A | 2 | NULL | NULL | | BTREE | |
| tableName | 1 | idx_colVlviID | 1 | colVlviID | A | 4133 | NULL | NULL | | BTREE | |
| tableName | 1 | idx_colSomeID | 1 | colSomeID | A | 10 | NULL | NULL | | BTREE | |
| tableName | 1 | idx_colVcamID | 1 | colVcamID | A | 7 | NULL | NULL | | BTREE | |
| tableName | 1 | idx_colVlnsID | 1 | colVlnsID | A | 18 | NULL | NULL | | BTREE | |
| tableName | 1 | idx_colCarrID | 1 | colCarrID | A | 4 | NULL | NULL | | BTREE | |
+-------+------------+-------------------------------+--------------+---------------------+-----------+-------------+----------+--------+------+------------+---------+
First up, you have far too may indexes. Most of those indexes are likely pointless. If you aren't using a specific index for WHERE criteria, JOINs, or ORDERing, then remove it as it just slows things down.
Next up, for your query you specify 3 columns that are always in the query comprising 1x DATE and 2x INT columns. The DATE column should be first as a date range is pretty fast on an index, and then the two INTs. This gives a starting point of the following 3-column index
CREATE INDEX searchIndex
ON tableName (ColDateStart,ColVlviID,ColVcamID)
USING BTREE;
More information on that available here : http://dev.mysql.com/doc/refman/5.0/en/multiple-column-indexes.html
I ordered the columns that way intentionally. ColDateStart for the date range filtering, followed by the other columns in decreasing order of cardinality. I selected ColVlviID as a second column as it has a cardinality of 4133 compared to ColVcamID having a cardinality of 7. This will allow MySQL to more efficiently reduce the matching rows.
Now, assuming colSomeID is the last column, I might instead do the following
CREATE INDEX searchIndex_someID
ON tableName (ColDateStart,ColVlviID,ColVcamID,ColSomeID)
USING BTREE;
This 3-column index will help MySQL get down to the applicable dataset before checking for that last ID. Optioanlly you could add a 4th column to that index at the end, if you are commonly filtering in another particular INT column.
As an aside, you may want to consider the following instead of the dateCol criteria
SELECT colID
FROM tableName
WHERE ColDateStart BETWEEN DATE('$lowerDate') AND DATE('$upperDate')
AND ColVcamID=$id1
AND ColVlviID=$id2
AND ColSomeID=$id3
The above all of course assumes that you are sanitising the variables before executing the query. I have removed the quotes from the $idx variables, as they should be numeric and therefore do not need to be entered as strings.
SELECT id
FROM tableName FORCE INDEX(`idx_otherId2`)
WHERE dateCol <='$lowerDate'
AND dateCol>='$upperDate'
AND otherId1='$id1'
AND otherId2='$id2'
AND otherId3='$id3';
Related
I have this query and it takes ages (about 10 min) to complete.
SELECT COUNT(DISTINCT(column)) var,
column2 var2
FROM table
WHERE column<>'X' and
column2 between 'Y' and 'Z'
GROUP BY var2
ORDER BY var DESC
Any ideas how to optimize for speed? I tried with indexes but still slow. Maybe they are not set properly. Y and Z are timestamps, if it matters, and X is something that is not needed at all for this query but is in the table for it is needed for other queries from the same app. The table is very large - millions of rows, and it is yet to grow.
Edit: Here is the EXPLAIN result from an example:
mysql> EXPLAIN SELECT COUNT(DISTINCT(ip)) v, geo n from idevaff_iptracking where geo<>'XX' and stamp between '1525122000' and '1543615199' group by n order by v desc;
+------+-------------+--------------------+-------+------------------------+--------------+---------+------+---------+-----------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+--------------------+-------+------------------------+--------------+---------+------+---------+-----------------------------------------------------------+
| 1 | SIMPLE | idevaff_iptracking | range | stamp,geo,geo_stamp_ip | geo_stamp_ip | 9 | NULL | 3469323 | Using where; Using index; Using temporary; Using filesort |
+------+-------------+--------------------+-------+------------------------+--------------+---------+------+---------+-----------------------------------------------------------+
1 row in set (0.00 sec)
Table locums are as follows:
id,acct_id,ip,refer,stamp,hit_time,hit_date,src1,src2,split,sub_id,tid1,tid2,tid3,tid4,target_url,geo.
Indexes are as follows:
mysql> SHOW INDEX FROM idevaff_iptracking
-> ;
+--------------------+------------+--------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+--------------------+------------+--------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| idevaff_iptracking | 0 | PRIMARY | 1 | id | A | 6775984 | NULL | NULL | | BTREE | | |
| idevaff_iptracking | 1 | acct_id_ip | 1 | acct_id | A | 2 | NULL | NULL | | BTREE | | |
| idevaff_iptracking | 1 | acct_id_ip | 2 | ip | A | 6775984 | NULL | NULL | YES | BTREE | | |
| idevaff_iptracking | 1 | ip | 1 | ip | A | 6775984 | NULL | NULL | YES | BTREE | | |
| idevaff_iptracking | 1 | stamp | 1 | stamp | A | 6775984 | NULL | NULL | | BTREE | | |
| idevaff_iptracking | 1 | acct_id | 1 | acct_id | A | 4 | NULL | NULL | | BTREE | | |
| idevaff_iptracking | 1 | geo | 1 | geo | A | 440 | NULL | NULL | YES | BTREE | | |
| idevaff_iptracking | 1 | tid1 | 1 | tid1 | A | 276 | NULL | NULL | YES | BTREE | | |
| idevaff_iptracking | 1 | tid2 | 1 | tid2 | A | 514 | NULL | NULL | YES | BTREE | | |
| idevaff_iptracking | 1 | tid3 | 1 | tid3 | A | 34 | NULL | NULL | YES | BTREE | | |
| idevaff_iptracking | 1 | tid4 | 1 | tid4 | A | 5623 | NULL | NULL | YES | BTREE | | |
| idevaff_iptracking | 1 | acct_id_stamp_ip | 1 | acct_id | A | 744 | NULL | NULL | | BTREE | | |
| idevaff_iptracking | 1 | acct_id_stamp_ip | 2 | stamp | A | 6775984 | NULL | NULL | | BTREE | | |
| idevaff_iptracking | 1 | acct_id_stamp_ip | 3 | ip | A | 6775984 | NULL | NULL | YES | BTREE | | |
| idevaff_iptracking | 1 | geo_stamp_ip | 1 | geo | A | 22362 | NULL | NULL | YES | BTREE | | |
| idevaff_iptracking | 1 | geo_stamp_ip | 2 | stamp | A | 6775984 | NULL | NULL | | BTREE | | |
| idevaff_iptracking | 1 | geo_stamp_ip | 3 | ip | A | 6775984 | NULL | NULL | YES | BTREE | | |
| idevaff_iptracking | 1 | acct_id_tid1_stamp | 1 | acct_id | A | 658 | NULL | NULL | | BTREE | | |
| idevaff_iptracking | 1 | acct_id_tid1_stamp | 2 | tid1 | A | 11866 | NULL | NULL | YES | BTREE | | |
| idevaff_iptracking | 1 | acct_id_tid1_stamp | 3 | stamp | A | 6775984 | NULL | NULL | | BTREE | | |
| idevaff_iptracking | 1 | acct_id_tid2_stamp | 1 | acct_id | A | 2 | NULL | NULL | | BTREE | | |
| idevaff_iptracking | 1 | acct_id_tid2_stamp | 2 | tid2 | A | 18666 | NULL | NULL | YES | BTREE | | |
| idevaff_iptracking | 1 | acct_id_tid2_stamp | 3 | stamp | A | 6775984 | NULL | NULL | | BTREE | | |
| idevaff_iptracking | 1 | acct_id_tid3_stamp | 1 | acct_id | A | 2 | NULL | NULL | | BTREE | | |
| idevaff_iptracking | 1 | acct_id_tid3_stamp | 2 | tid3 | A | 1832 | NULL | NULL | YES | BTREE | | |
| idevaff_iptracking | 1 | acct_id_tid3_stamp | 3 | stamp | A | 6775984 | NULL | NULL | | BTREE | | |
| idevaff_iptracking | 1 | acct_id_tid4_stamp | 1 | acct_id | A | 2 | NULL | NULL | | BTREE | | |
| idevaff_iptracking | 1 | acct_id_tid4_stamp | 2 | tid4 | A | 5060 | NULL | NULL | YES | BTREE | | |
| idevaff_iptracking | 1 | acct_id_tid4_stamp | 3 | stamp | A | 6775984 | NULL | NULL | | BTREE | | |
+--------------------+------------+--------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
29 rows in set (0.00 sec)
Add this composite index:
INDEX(column2, column)
If that does not suffice, we need to see SHOW CREATE TABLE in order to discuss further. (geo_stamp_ip is not as good.)
It is usually a mistake to splay an array (the tid's) across columns.
EXPLAIN FORMAT=JSON
SELECT COUNT(DISTINCT ip) v, geo n
from idevaff_iptracking
where geo<>'XX'
and stamp between '1525122000' AND '1543615199'
group by n
order by v desc;
Some of the indexes are redundant. In general, INDEX(a) can be removed if you have INDEX(a,b). (For example: acct_id_ip)
Hello i am trying to run this select statement using this query and it is taking over 2 hours to run. I have set up all the index's to be correct. But it still takes forever is there something i am missing or a more efficient way of joining tables together that will speed this query up?
I have indexes set up for all items being joined together and they are the same length and data type.
SELECT
p.sap_article_id,
p.numeric_line_code,
p.uag_linecode,
p.uag_partnum,
p.part_description,
p.jobber_price,
p.jobber_core,
p.discount1,
p.discount2,
p.uom,
p.product_category,
w.as400_warehouse,
w.atp_qty,
p.updated,
t.regular_discount
FROM part p
LEFT JOIN tabjbmaw t ON t.accountnum = '73050'
AND p.numeric_line_code = t.numeric_line_code
AND p.sub_code = t.sub_code
JOIN warehouse w ON w.sap_article_id = p.sap_article_id;
+----+-------------+-----------+------+--------------------------------------------------+-----------------------+---------+----------------------------------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+--------------------------------------------------+-----------------------+---------+----------------------------------+--------+-------------+
| 1 | SIMPLE | part | ALL | PRIMARY,sap_article,part_sap_article_id_fk | NULL | NULL | NULL | 389309 | |
| 1 | SIMPLE | warehouse | ref | article | article | 130 | inventory.part.sap_article_id | 5 | Using where |
| 1 | SIMPLE | tabjbmaw | ref | numeric_line_code_idx,subcode_idx,accountnum_idx | numeric_line_code_idx | 5 | inventory.part.numeric_line_code | 19 | |
+----+-------------+-----------+------+--------------------------------------------------+-----------------------+---------+----------------------------------+--------+-------------+
Thank you for your help
+-----------------------------+--------------+------+-----+---------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------------------+--------------+------+-----+---------------------+-----------------------------+
| sap_article_id | varchar(24) | NO | PRI | | |
| sap_brand_id | varchar(20) | NO | | NULL | |
| uag_partnum | varchar(20) | NO | MUL | NULL | |
| uag_linecode | varchar(5) | NO | MUL | NULL | |
| cag_partnum | varchar(20) | NO | MUL | NULL | |
| cag_linecode | varchar(5) | NO | | NULL | |
| product_category_legacy | varchar(20) | NO | | NULL | |
| part_description | varchar(128) | NO | | NULL | |
| abc_indicator | varchar(8) | NO | | NULL | |
| pack_code | varchar(8) | NO | | NULL | |
| case_qty | int(11) | NO | | NULL | |
| per_car_qty | int(11) | NO | | NULL | |
| uom | varchar(6) | NO | | NULL | |
| upc_code | varchar(128) | NO | | NULL | |
| jobber_price | float(14,4) | YES | | NULL | |
| jobber_core | float(14,4) | YES | | NULL | |
| date_last_price_change | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| weight | float(14,4) | YES | | NULL | |
| weight_unit | varchar(6) | NO | | NULL | |
| dimension_type | varchar(6) | NO | | NULL | |
| length | float(14,4) | YES | | NULL | |
| width | float(14,4) | YES | | NULL | |
| height | float(14,4) | YES | | NULL | |
| updated | tinyint(1) | NO | | 0 | |
| superseded_sap_article_id | varchar(24) | YES | | NULL | |
| last_updated | timestamp | NO | | 0000-00-00 00:00:00 | |
| hour_updated | int(11) | YES | | NULL | |
| discount1 | float | YES | | NULL | |
| discount2 | float | YES | | NULL | |
| product_category | varchar(3) | YES | | NULL | |
| superseded_part_number | varchar(20) | YES | | NULL | |
| sub_code | varchar(3) | YES | MUL | NULL | |
| date_effective_price_change | date | YES | | NULL | |
| numeric_line_code | varchar(3) | YES | MUL | NULL | |
| list | float | YES | | NULL | |
+-----------------------------+--------------+------+-----+---------------------+-----------------------------+
I have indexes set up for all items being joined together
Yes, but I am guessing from the names of the indexes that each index only has one field.
Let's look at a few columns in the describe.
| table | possible_keys | key
+-----------+--------------------------------------------------+----------------
| part | PRIMARY,sap_article,part_sap_article_id_fk | NULL
| warehouse | article | article
| tabjbmaw | numeric_line_code_idx,subcode_idx,accountnum_idx | numeric_line_code_idx
It can use an index for numeric_line_code, subcode, and accountnum, but there are only three indexes each with one of the fields, and no index which has all the fields. You are making the optimizer choose one of the one field indexes, instead of providing one index it can use for all three fields.
Add an index on table tabjbmaw with the three fields numeric_line_code, subcode, and accountnum.
Extending #Sebas answer, you should select tabjbmaw first:
SELECT
p.sap_article_id,
p.numeric_line_code,
p.uag_linecode,
p.uag_partnum,
p.part_description,
p.jobber_price,
p.jobber_core,
p.discount1,
p.discount2,
p.uom,
p.product_category,
w.as400_warehouse,
w.atp_qty,
p.updated,
t.regular_discount
FROM tabjbmaw t
LEFT JOIN parts p ON p.numeric_line_code = t.numeric_line_code
AND p.sub_code = t.sub_code
JOIN warehouse w ON w.sap_article_id = p.sap_article_id
WHERE t.accountnum = '73050'
;
You could try to put your Left Join into the SELECT part as a Subselect. That 'may' speed things up a little.
Like this:
SELECT
p.sap_article_id,
p.numeric_line_code,
p.uag_linecode,
p.uag_partnum,
p.part_description,
p.jobber_price,
p.jobber_core,
p.discount1,
p.discount2,
p.uom,
p.product_category,
w.as400_warehouse,
w.atp_qty,
p.updated,
(SELECT t.regular_discount FROM tabjbmaw t WHERE t.accountnum = '73050' AND p.numeric_line_code = t.numeric_line_code AND p.sub_code = t.sub_code LIMIT 1)
FROM
part p
JOIN warehouse w ON w.sap_article_id = p.sap_article_id;
I have a query that is using a group by and an order by, but it's very slow! I need some help to get the index correct. This is the query I'm running:
select *
from puresen_mv_shop.cache_deals
where feature_ids REGEXP 'i,t,d'
and phone_cost > 100.00
group by handset_numeric_id
order by popularity
LIMIT 0,10;
explain:
1 SIMPLE cache_deals index popularity 5 10 6635320.00 Using where; Using temporary
This runs in about 3 seconds, but I need it under a second. There are over 600k rows in the table. Here is the table structure:
mysql> describe cache_deals
-> ;
+-------------------------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------------------+---------------+------+-----+---------+-------+
| deal_id | varchar(100) | NO | | NULL | |
| deal_id_replication | varchar(150) | NO | PRI | | |
| handset_numeric_id | int(10) | YES | MUL | NULL | |
| handset_url | varchar(100) | YES | | NULL | |
| image_url | varchar(50) | YES | MUL | NULL | |
| handset_id | varchar(50) | YES | | NULL | |
| phone_cost | decimal(10,2) | YES | | NULL | |
| tariff_numeric_id | int(10) | YES | MUL | NULL | |
| tariff_id | varchar(100) | YES | MUL | NULL | |
| tariff_name | varchar(100) | YES | | NULL | |
| network_name | varchar(20) | YES | | NULL | |
| network_numeric_id | int(5) | YES | MUL | NULL | |
| term | int(5) | YES | MUL | NULL | |
| minutes | int(5) | YES | MUL | NULL | |
| texts | int(5) | YES | MUL | NULL | |
| data | int(5) | YES | MUL | NULL | |
| org_line_rental | decimal(10,2) | YES | MUL | NULL | |
| effective_monthly_cost | decimal(10,2) | YES | MUL | NULL | |
| free_gift_id | int(10) | YES | MUL | NULL | |
| free_gift_name | varchar(50) | YES | | NULL | |
| cashback | int(5) | YES | MUL | NULL | |
| free_lr | int(5) | YES | MUL | NULL | |
| half_lr | int(5) | YES | MUL | NULL | |
| clearance_flag | int(5) | YES | MUL | NULL | |
| manufacturer_numeric_id | int(5) | YES | MUL | NULL | |
| manufacturer_name | varchar(50) | YES | | NULL | |
| full_handset_name | varchar(100) | YES | | NULL | |
| popularity | int(20) | YES | MUL | NULL | |
| handset_colour | varchar(50) | YES | MUL | NULL | |
| feature_ids | varchar(100) | YES | | NULL | |
| operating_system | varchar(30) | YES | MUL | NULL | |
+-------------------------+---------------+------+-----+---------+-------+
Here are the indexes I've currently got on this table:
mysql> show index from cache_deals;
+-------------+------------+-------------------------+--------------+-------------------------+-----------+-------------+----------+--------+------+------------
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type
+-------------+------------+-------------------------+--------------+-------------------------+-----------+-------------+----------+--------+------+------------
| cache_deals | 0 | PRIMARY | 1 | deal_id_replication | A | 663532 | NULL | NULL | | BTREE
| | |
| cache_deals | 1 | handset_numeric_id | 1 | handset_numeric_id | A | 759 | NULL | NULL | YES | BTREE
| | |
| cache_deals | 1 | network_numeric_id | 1 | network_numeric_id | A | 8 | NULL | NULL | YES | BTREE
| | |
| cache_deals | 1 | tariff_numeric_id | 1 | tariff_numeric_id | A | 1091 | NULL | NULL | YES | BTREE
| | |
| cache_deals | 1 | manufacturer_numeric_id | 1 | manufacturer_numeric_id | A | 23 | NULL | NULL | YES | BTREE
| | |
| cache_deals | 1 | operating_system | 1 | operating_system | A | 42 | NULL | NULL | YES | BTREE
| | |
| cache_deals | 1 | image_url | 1 | image_url | A | 755 | NULL | NULL | YES | BTREE
| | |
| cache_deals | 1 | tariff_id | 1 | tariff_id | A | 1091 | NULL | NULL | YES | BTREE
| | |
| cache_deals | 1 | term | 1 | term | A | 7 | NULL | NULL | YES | BTREE
| | |
| cache_deals | 1 | minutes | 1 | minutes | A | 26 | NULL | NULL | YES | BTREE
| | |
| cache_deals | 1 | texts | 1 | texts | A | 14 | NULL | NULL | YES | BTREE
| | |
| cache_deals | 1 | data | 1 | data | A | 14 | NULL | NULL | YES | BTREE
| | |
| cache_deals | 1 | org_line_rental | 1 | org_line_rental | A | 128 | NULL | NULL | YES | BTREE
| | |
| cache_deals | 1 | effective_monthly_cost | 1 | effective_monthly_cost | A | 2147 | NULL | NULL | YES | BTREE
| | |
| cache_deals | 1 | free_gift_id | 1 | free_gift_id | A | 105 | NULL | NULL | YES | BTREE
| | |
| cache_deals | 1 | cashback | 1 | cashback | A | 2 | NULL | NULL | YES | BTREE
| | |
| cache_deals | 1 | free_lr | 1 | free_lr | A | 2 | NULL | NULL | YES | BTREE
| | |
| cache_deals | 1 | half_lr | 1 | half_lr | A | 2 | NULL | NULL | YES | BTREE
| | |
| cache_deals | 1 | clearance_flag | 1 | clearance_flag | A | 2 | NULL | NULL | YES | BTREE
| | |
| cache_deals | 1 | handset_colour | 1 | handset_colour | A | 17 | NULL | NULL | YES | BTREE
| | |
| cache_deals | 1 | popularity | 1 | popularity | A | 718 | NULL | NULL | YES | BTREE
| | |
+-------------+------------+-------------------------+--------------+-------------------------+-----------+-------------+----------+--------+------+------------
Am I indexing this table correctly?
Thanks for you help.
That REGEXP is killing the potential performance since it can't use an index. Can that part of the query be written some other way or possibly normalized to another table? If you can, that will probably help. Other than that, a composite index on phone_cost and handset_numeric_id should help. Also adding popularity to that index might help, but MySQL is already unhappy with the query since you're not really supposed to be able to work with columns that aren't in the GROUP BY clause.
As a side note, the data types of the columns could be more efficient. int(5) works the same as MEDIUMINT due to the limit on the INT except that MEDIUMINT is one byte smaller. Also, int(20) doesn't make sense since the INT type can't be that large.
select [name the columns you actually want returned]
from puresen_mv_shop.cache_deals
where feature_ids = 'i,t,d'
and phone_cost > 100.00
order
by popularity
LIMIT 0,10;
Index features_id or (features_id,phone_cost)
I'm trying to run the following query:
SELECT formatted_journeys.*, MAX(speed)
FROM formatted_journeys
JOIN tracker.g_log
ON imeiid = vehicle
AND g_logid BETWEEN start_g_log AND end_g_log
GROUP BY id
however, it seems to be extremely slow. Here's the explain for that query.
+----+-------------+--------------------+------+-------------------------------+-------+---------+-----------------------------------+------+----------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------------------+------+-------------------------------+-------+---------+-----------------------------------+------+----------+---------------------------------+
| 1 | SIMPLE | formatted_journeys | ALL | vehicle,start_g_log,end_g_log | NULL | NULL | NULL | 824 | 100.00 | Using temporary; Using filesort |
| 1 | SIMPLE | g_log | ref | PRIMARY,Dupes | Dupes | 4 | motrak.formatted_journeys.vehicle | 1985 | 100.00 | Using where |
+----+-------------+--------------------+------+-------------------------------+-------+---------+-----------------------------------+------+----------+---------------------------------+
2 rows in set, 1 warning (0.02 sec)
The tables are as follows:
formatted_journeys:
+-----------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| start_g_log | int(11) | YES | MUL | NULL | |
| end_g_log | int(11) | YES | MUL | NULL | |
| start_latitude | decimal(18,12) | YES | | NULL | |
| start_longitude | decimal(18,12) | YES | | NULL | |
| end_latitude | decimal(18,12) | YES | | NULL | |
| end_longitude | decimal(18,12) | YES | | NULL | |
| start_location | text | YES | | NULL | |
| end_location | text | YES | | NULL | |
| distance | decimal(10,5) | YES | | NULL | |
| start_date | datetime | YES | | NULL | |
| end_date | datetime | YES | | NULL | |
| vehicle | int(11) | YES | MUL | NULL | |
| private | bit(1) | NO | | b'0' | |
+-----------------+------------------+------+-----+---------+----------------+
Indices:
+--------------------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+--------------------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| formatted_journeys | 0 | PRIMARY | 1 | id | A | 830 | NULL | NULL | | BTREE | |
| formatted_journeys | 1 | vehicle | 1 | vehicle | A | 4 | NULL | NULL | YES | BTREE | |
| formatted_journeys | 1 | start_g_log | 1 | start_g_log | A | 830 | NULL | NULL | YES | BTREE | |
| formatted_journeys | 1 | end_g_log | 1 | end_g_log | A | 830 | NULL | NULL | YES | BTREE | |
+--------------------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
tracker.g_log:
+-----------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+------------------+------+-----+---------+----------------+
| g_logid | int(10) unsigned | NO | PRI | NULL | auto_increment |
| imeiid | int(10) unsigned | NO | MUL | NULL | |
| latitude | decimal(18,12) | YES | | NULL | |
| longitude | decimal(18,12) | YES | | NULL | |
| speed | int(4) | YES | MUL | NULL | |
| bearing | int(4) | YES | | NULL | |
| distance | decimal(10,5) | YES | | NULL | |
| eventcode | int(10) | YES | | NULL | |
| status | int(10) | YES | | NULL | |
| date | datetime | YES | | NULL | |
+-----------+------------------+------+-----+---------+----------------+
Indices:
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| g_log | 0 | PRIMARY | 1 | g_logid | A | 31760 | NULL | NULL | | BTREE | |
| g_log | 0 | Dupes | 1 | imeiid | A | 16 | NULL | NULL | | BTREE | |
| g_log | 0 | Dupes | 2 | date | A | 31760 | NULL | NULL | YES | BTREE | |
| g_log | 0 | Dupes | 3 | eventcode | A | 31760 | NULL | NULL | YES | BTREE | |
| g_log | 1 | speed | 1 | speed | A | 423 | NULL | NULL | YES | BTREE | |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
Now I know that the filesort isn't a good thing but how would I get rid of it?
You will hardly get rid of Using temporary; Using filesort, but the query might be faster.
First, try to rewrite the query as:
SELECT *
FROM (
SELECT id, MAX(speed) as max_speed
FROM formatted_journeys
JOIN tracker.g_log
ON imeiid = vehicle
AND g_logid BETWEEN start_g_log AND end_g_log
GROUP BY id) as maxspeeds
JOIN formatted_journeys USING (id);
Then, you can try to force the query to use a coverage index, though that is not easy for the query.
First try: add a composite index (vehicle, start_g_log, end_g_log) and look in explain whether it is used (you should see "Using index" there)
I am trying to optimize a MySQL select request:
SELECT * FROM `sales`
WHERE ((sales.private = false AND (sales.buyer_id IS NULL OR NOT sales.buyer_id=142)
AND (sales.merchand_id IS NULL OR NOT sales.merchand_id=142)
AND (sales.private_item = false) )
AND ((sales.buyer_id=32 OR sales.merchand_id=32)
AND (sales.admin=0 AND NOT sales.type IN ('book'))))
ORDER BY sales.created_at DESC, sales.id DESC LIMIT 0, 10;
The schema of the table is
mysql> SHOW columns from sales;
+------------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| type | varchar(255) | YES | MUL | NULL | |
| buyer_id | int(11) | YES | MUL | NULL | |
| merchand_id | int(11) | YES | MUL | NULL | |
| private | tinyint(1) | YES | | 0 | |
| admin | tinyint(1) | YES | | 0 | |
| created_at | datetime | YES | | NULL | |
| updated_at | datetime | YES | | NULL | |
| country_id | int(11) | YES | MUL | 0 | |
| private_item | tinyint(1) | YES | | 0 | |
+------------------------+--------------+------+-----+---------+----------------+
The indexes are:
mysql> show indexes from sales;
+-----------------+------------+--------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-----------------+------------+--------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| sales | 0 | PRIMARY | 1 | id | A | 286509 | NULL | NULL | | BTREE | |
| sales | 1 | index_sales_on_type | 1 | type | A | 123 | NULL | NULL | YES | BTREE | |
| sales | 1 | index_sales_on_buyer_id | 1 | buyer_id | A | 40929 | NULL | NULL | YES | BTREE | |
| sales | 1 | index_sales_on_merchand_id | 1 | merchand_id | A | 40929 | NULL | NULL | YES | BTREE | |
| sales | 1 | index_sales_on_country_id | 1 | country_id | A | 6 | NULL | NULL | YES | BTREE | |
| sales | 1 | index_sales_on_type_and_country_id | 1 | type | A | 151 | NULL | NULL | YES | BTREE | |
| sales | 1 | index_sales_on_type_and_country_id | 2 | country_id | A | 428 | NULL | NULL | YES | BTREE | |
| sales | 1 | index_sales_viewed | 1 | buyer_id | A | 35813 | NULL | NULL | YES | BTREE | |
| sales | 1 | index_sales_viewed | 2 | merchand_id | A | 286509 | NULL | NULL | YES | BTREE | |
| sales | 1 | index_sales_viewed | 3 | private_item| A | 285009 | NULL | NULL | YES | BTREE | |
| sales | 1 | index_sales_viewed | 4 | admin | A | 285009 | NULL | NULL | YES | BTREE | |
| sales | 1 | index_sales_viewed | 5 | type | A | 285009 | NULL | NULL | YES | BTREE | |
| sales | 1 | index_sales_viewed | 6 | private | A | 285009 | NULL | NULL | YES | BTREE | |
| sales | 1 | index_sales_viewed | 7 | created_at | A | 285009 | NULL | NULL | YES | BTREE | |
+-------+------------+------------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
When doing the query it uses the index_sales_on_type_and_country_id even if there is no country_id in the query...
The query takes 2.5 seconds with this index.
But when I use USE INDEX(index_sales_viewed) it goes down to 0.2 seconds.
Here is the EXPLAIN of the query:
+----+-------------+-----------------+------+----------------------------------------------+------+---------+------+--------+---------------------
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------------+------+----------------------------------------------+------+---------+------+--------+---------------------
| 1 | SIMPLE | sales | range | see bellow | index_sales_on_type_and_country_id | 258 | NULL | 208725 | Using where; Using filesort |
+----+-------------+-----------------+------+----------------------------------------------+------+---------+------+--------+---------------------
the possible keys are :
index_sales_on_type,
index_sales_on_buyer_id,
index_sales_on_merchand_id,
index_sales_on_type_and_country_id,
index_sales_public_recent_activity
Why doesn't MySQL use index_sales_viewed by default? Could there be a better index?
Thank you!
This is wrong use on NULL, please change all the column used in the index to be NOT NULL
refer this When to use NULL in MySQL tables
official documentation
If this column is NULL, there are no relevant indexes. In this case, you may be able to improve the performance of your query by examining the WHERE clause to check whether it refers to some column or columns that would be suitable for indexing. If so, create an appropriate index and check the query with EXPLAIN again
Mysql chosen index index_sales_on_type_and_country_id because you are not compare with NULL value