How to make MySQl update faster for large tables - mysql

I would like to optimise an update query of this table as it currently takes a couple of seconds to execute. I am using MySQL 5.6
UPDATE skus1 SET `available` = '1', `locked` = NULL WHERE `locked` IS NOT NULL AND `locked` < (NOW() - INTERVAL 30 MINUTE)
I would like to optimise this query also
UPDATE skus1 SET `available` = '2', `locked` = NOW() WHERE sku = '111111'
I have a SELECT query that runs fast now I've added my indexes
Here is my table structure
CREATE TABLE `skus1` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`sku` varchar(9) NOT NULL,
`available` tinyint(1) NOT NULL DEFAULT '1',
`locked` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `sku_2` (`sku`,`locked`),
KEY `available` (`available`),
KEY `locked` (`locked`),
KEY `sku` (`sku`)
) ENGINE=MyISAM AUTO_INCREMENT=500001 DEFAULT CHARSET=utf8

Related

MySQL 8.0.26 Slow Query When Counting Results on Three Tables with Indexes

I have a statistics page on my internal admin site to show some traffic information on individual sites. However, the query is taking nearly 80 seconds to run, even with Indexes placed on the keys for each of the tables.
I'm typically running this query searching for session status within 7 days of the date ran.
SELECT
*,
(
SELECT
COUNT(`session_id`)
FROM
`my-db`.`sessions`
WHERE
`my-db`.`sessions`.`site_id` = `my-db`.`sites`.`site_id`
AND `session_datetime` > '2021-10-17 00:00:00'
) as session_count,
(
SELECT
`session_datetime`
FROM
`my-db`.`sessions`
WHERE
`my-db`.`sessions`.`site_id` = `my-db`.`sites`.`site_id`
AND `session_datetime` > '2021-10-17 00:00:00'
ORDER BY
`session_id` ASC
LIMIT
1
) as first_session,
(
SELECT
`session_datetime`
FROM
`my-db`.`sessions`
WHERE
`my-db`.`sessions`.`site_id` = `my-db`.`sites`.`site_id`
AND `session_datetime` > '2021-10-17 00:00:00'
ORDER BY
`session_id` DESC
LIMIT
1
) as last_session,
(
SELECT
COUNT(`site_profiles_id`)
FROM
`my-db`.`sites_profiles`
WHERE
`my-db`.`sites_profiles`.`site_id` = `my-db`.`sites`.`site_id`
AND `origin` = 1
AND `date_added` > '2021-10-17 00:00:00'
) as profiles_originated,
(
SELECT
COUNT(`site_profiles_id`)
FROM
`my-db`.`sites_profiles`
WHERE
`my-db`.`sites_profiles`.`site_id` = `my-db`.`sites`.`site_id`
AND `scanned` = 1
AND `date_added` > '2021-10-17 00:00:00'
) as profiles_scanned,
(
SELECT
COUNT(`site_profiles_id`)
FROM
`my-db`.`sites_profiles`
WHERE
`my-db`.`sites_profiles`.`site_id` = `my-db`.`sites`.`site_id`
AND `date_added` > '2021-10-17 00:00:00'
) as profiles_collected
FROM
`my-db`.`sites`
WHERE
`site_id` in (
SELECT
DISTINCT(`site_id`)
FROM
`my-db`.`sessions`
WHERE
`session_datetime` > '2021-10-17 00:00:00'
)
ORDER BY
`session_count` DESC
LIMIT
25;
I'm trying to understand the results of EXPLAIN, but I believe the issue is because of the RANGE type of the index used on the datetime.
It's worth noting, I'm dynamically changing the ORDER BY clause depending on a sort dropdown selected by the admin user to sort the results by - site_id ASC/DESC, session_count ASC/DESC and profiles_collected ASC/DESC.
The performance of the profiles_collected DESC is significantly impacted when compared to the others.
network_sites
CREATE TABLE `sites` (
`site_id` bigint NOT NULL AUTO_INCREMENT,
`account_id` bigint NOT NULL,
`site_hash` varchar(128) CHARACTER SET utf8 NOT NULL,
`site_address` varchar(255) CHARACTER SET utf8 NOT NULL,
`site_status` int NOT NULL,
`site_created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`site_updated` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`site_id`),
UNIQUE KEY `site_id_UNIQUE` (`site_id`),
UNIQUE KEY `site_hash_UNIQUE` (`site_hash`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
network_profiles_sessions
CREATE TABLE `sessions` (
`session_id` bigint NOT NULL AUTO_INCREMENT,
`site_id` bigint NOT NULL,
`profile_id` bigint DEFAULT NULL,
`session_hash` varchar(128) CHARACTER SET utf8 NOT NULL,
`session_ip_address` varchar(45) CHARACTER SET utf8 DEFAULT NULL,
`session_useragent` text CHARACTER SET utf8,
`session_page_uri` text CHARACTER SET utf8,
`session_datetime` datetime DEFAULT CURRENT_TIMESTAMP,
`session_has_data` tinyint DEFAULT '0',
`session_processed` tinyint DEFAULT '0',
`session_queued` tinyint DEFAULT '0',
PRIMARY KEY (`session_id`),
UNIQUE KEY `session_id_UNIQUE` (`session_id`),
KEY `session_has_data` (`session_has_data`,`session_id`),
KEY `session_processed` (`session_processed`,`session_id`),
KEY `session_queued` (`session_queued`,`session_id`),
KEY `session_datetime` (`session_datetime`,`session_id`),
KEY `session_hash` (`session_hash`,`session_id`),
KEY `site_id` (`site_id`,`session_id`),
FULLTEXT KEY `session_page_uri` (`session_page_uri`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
network_sites_profiles
CREATE TABLE `sites_profiles` (
`site_profiles_id` bigint NOT NULL AUTO_INCREMENT,
`site_id` bigint NOT NULL,
`profile_id` bigint NOT NULL,
`origin` int DEFAULT NULL,
`scanned` int DEFAULT NULL,
`date_added` datetime DEFAULT CURRENT_TIMESTAMP,
`date_lastseen` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`site_profiles_id`),
UNIQUE KEY `site_users_id_UNIQUE` (`site_profiles_id`),
KEY `site_id` (`site_id`,`site_profiles_id`),
KEY `date_added` (`date_added` DESC,`site_profiles_id`),
KEY `origin` (`origin`,`site_profiles_id`),
KEY `scanned` (`scanned`,`site_profiles_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
PRIMARY KEY(a)
UNIQUE KEY(a) -- redundant, DROP it
A PK is a UNIQUE key is an INDEX.
The last 3 subqueries can be combined:
SELECT SUM(origin = 1) AS profiles_originated,
SUM(scanned = 1) AS profiles_scanned,
COUNT(*) AS profiles_collected
FROM profiles
WHERE date_added >= '2021-10-17'
And then JOIN to that. However, there are some potential problems...
How do session.datetime and date_added compare? I'm assuming that a session is added before it happens?
I assume you want to include midnight of the morning of Oct 17?
The first 3 subqueries can perhaps be similarly simplified. Note that MAX(session_datetime) is sufficient for last_session.

Mysq l - Slow one update query in large table

i have a three almost identical queries executed one by one in my app. Two of queries are executing fairly fast but one is much slower. Here are queries:
update `supremeshop_product_attributes` set `id_step` = 899 where `id_step` = 1 and `id_product` = 32641
540ms
update `supremeshop_product_attributes` set `id_step` = 1 where `id_step` = 0 and `id_product` = 32641
1.71s
update `supremeshop_product_attributes` set `id_step` = 0 where `id_step` = 899 and `id_product` = 32641
9.75ms
Create table query
CREATE TABLE `supremeshop_product_attributes` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`id_product` int(11) NOT NULL,
`id_attribute` int(11) NOT NULL,
`id_attribute_group` int(11) NOT NULL,
`id_step` int(11) NOT NULL,
`id_alias` int(9) NOT NULL,
`price_retail` int(11) NOT NULL DEFAULT '0',
`behaviour` int(1) NOT NULL DEFAULT '0',
`active` int(1) NOT NULL DEFAULT '1',
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `supremeshop_product_attributes_id_product_index` (`id_product`),
KEY `supremeshop_product_attributes_id_attribute_index` (`id_attribute`),
KEY `supremeshop_product_attributes_id_attribute_group_index` (`id_attribute_group`),
KEY `supremeshop_product_attributes_id_step_index` (`id_step`)
) ENGINE=InnoDB AUTO_INCREMENT=3012991 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
Facts:
table has 1500000 rows
each query updates around 650 rows
each searched/updated field has index (id(primary), id_product, id_step, id_alias)
only second query takes much longer time to execute (everytime - even executed as single query not one by one)
each variable used in query is integer
if i execute queries direcly in phpymysql -> sql - i get the same execution time (like in my laravel app so query is somehow slow)
Question is why? And is there a good explanation/ fix for that problem.
For any help many thanks!
Mark.

Optimise a MySQL query

I am using MySQL 8.0.20 and I have a huge table with some data in it.
CREATE TABLE `db_table` (
`utcDateTime` datetime DEFAULT NULL,
`dateTime` datetime DEFAULT NULL,
`col1` varchar(250) DEFAULT NULL,
`col2` varchar(10) DEFAULT NULL,
`col3` varchar(5) NOT NULL DEFAULT '1',
`col4` varchar(5) NOT NULL DEFAULT '1',
`id` int NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_dateIns` (`utcDateTime`,`col2`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8'
Below is the query I am trying to optimise,
SELECT col3,col4
from db_table
WHERE col2='123456'
AND (dateTime BETWEEN '2020-11-25 00:01' AND '2020-11-26 00:00')
group by utcDateTime
order by utcDateTime asc limit 1;
This query takes about 12 seconds to execute. But if I change the sorting order to desc, it takes about 0.015 seconds.
Can someone please help optimise the query or the database table?
Thank you

MySQL Insert Slow in AWS RDS

I'm trying to INSERT/UPDATE and realized it's taking about 15 seconds.
The table has only a few records (+/- 350 records) and is in an RDS instance db.t2.small
Table:
CREATE TABLE `ajustes` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`tipo_id` int(10) unsigned DEFAULT '1',
`nome` varchar(255) NOT NULL DEFAULT '',
`valor` text NOT NULL,
`array` tinyint(1) unsigned NOT NULL DEFAULT '0',
`created` datetime NOT NULL DEFAULT '1000-01-01 00:00:00',
`modified` datetime NOT NULL DEFAULT '1000-01-01 00:00:00',
PRIMARY KEY (`id`),
KEY `tipo_id` (`tipo_id`),
KEY `nome` (`nome`)
) ENGINE=InnoDB AUTO_INCREMENT=351 DEFAULT CHARSET=latin1;
I do not even know where to begin with.
I tried to use REPAIR but see the error:
The storage engine for the table doesn't support repair
I disabled two parameters and it works:
sync-binlog = 0
innodb_flush_log_at_trx_commit = 0

MySQL - optimize query

I don't know how to more optimize this query
SELECT COUNT(*)
FROM `job_offer` AS `o`
WHERE o.`status` = 1
AND EXISTS
( SELECT 1
FROM `job_offer_localitymap` AS lm
WHERE lm.`job_offerid` = o.`job_offerid`
AND lm.`gps_localityid` IN (116, 1)
)
Explain as image here: http://postimg.org/image/52wd06f3f/full/
It's simple select with subquery and it runs about 52 miliseconds on localhost, which is too much. There are many more records server and it runs 350miliseconds there. I also try this query replaced with inner join and group by with same results.
SELECT SQL_NO_CACHE COUNT(DISTINCT(o.job_offerid))
FROM `job_offer` AS `o`
INNER JOIN `job_offer_localitymap` AS lm ON lm.job_offerid = o.`job_offerid`
AND lm.`gps_localityid` IN (116, 1)
WHERE (o.`status` = 1)
Explain as image here: http://postimg.org/image/3renvl3gx/full/
I just don't get it why is that such a problem.
STATS: count returns 1415 rows, job_offer has 65k rows, job_offer_locality_map has 100k rows. All tables are MyISAM.
Thank you for suggestions.
Here is database dump (table job_offer has many rows - about 50-60, so I give here simple version)
DROP TABLE IF EXISTS `job_offer`;
CREATE TABLE `job_offer` (
`job_offerid` int(13) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`status` int(13) NOT NULL DEFAULT '1',
`sequence` int(13) NOT NULL DEFAULT '0',
`sequence_desc` tinyint(1) DEFAULT NULL,
`active_updated_when` datetime DEFAULT NULL,
PRIMARY KEY (`job_offerid`),
KEY `active_updated_when` (`active_updated_when`),
KEY `status_sequence_desc_active_updated_when_job_offerid` (`status`,`sequence_desc`,`active_updated_when`,`job_offerid`),
KEY `status_job_offerid` (`status`,`job_offerid`),
FULLTEXT KEY `name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `job_offer_localitymap`;
CREATE TABLE `job_offer_localitymap` (
`job_offer_localitymapid` int(13) NOT NULL AUTO_INCREMENT,
`old_id` int(13) NOT NULL DEFAULT '0',
`gps_localityid` int(13) NOT NULL,
`job_offerid` int(13) NOT NULL,
`sequence` int(13) NOT NULL DEFAULT '100',
`created` datetime NOT NULL,
`updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`old_localityid` int(13) NOT NULL DEFAULT '0',
PRIMARY KEY (`job_offer_localitymapid`),
KEY `job_offerid_gps_localityid` (`job_offerid`,`gps_localityid`),
KEY `job_offerid` (`job_offerid`),
KEY `gps_localityid` (`gps_localityid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INDEX(job_offered, gps_localityid)
Show us the JOIN version, together with its EXPLAIN and SHOW CREATE TABLE