Reputation: 297
I have 3 tables in which i store some values. Everything is working fine except my query is taking too long to execute. I have around 500.000 rows in table "tickets" at the moment. I would like to know what would be the best way to optimize this query to execute SELECT faster.
One more thing: I would like to know is there a way to update all rows through query (not using my C# app). In this case i need to update column "wonamount" which is in tickets with value that i get by multiplying row "coefficient" with row "uplata" and update column status with value "2".
Here are my tables and sql:
CREATE TABLE IF NOT EXISTS `coefficients` (`number` int(11) DEFAULT NULL,`coefficient` int(11) DEFAULT NULL) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `coefficients` (`number`, `coefficient`) VALUES
(1, 0),
(2, 0),
(3, 0),
(4, 0),
(5, 0),
(6, 10000),
(7, 7500),
(8, 5000),
(9, 2500),
(10, 1000),
(11, 500),
(12, 300),
(13, 200),
(14, 120),
(15, 80),
(16, 70),
(17, 60),
(18, 50),
(19, 40),
(20, 35),
(21, 30),
(22, 25),
(23, 20),
(24, 15),
(25, 12),
(26, 10),
(27, 9),
(28, 8),
(29, 7),
(30, 6),
(31, 5),
(32, 4),
(33, 3),
(34, 2),
(35, 1);
CREATE TABLE IF NOT EXISTS `draws` (
`iddraws` int(11) NOT NULL AUTO_INCREMENT,
`1` varchar(255) DEFAULT NULL,
`2` varchar(45) DEFAULT NULL,
`3` varchar(45) DEFAULT NULL,
`4` varchar(45) DEFAULT NULL,
`5` varchar(45) DEFAULT NULL,
`6` varchar(45) DEFAULT NULL,
`7` varchar(45) DEFAULT NULL,
`8` varchar(45) DEFAULT NULL,
`9` varchar(45) DEFAULT NULL,
`10` varchar(45) DEFAULT NULL,
`11` varchar(45) DEFAULT NULL,
`12` varchar(45) DEFAULT NULL,
`13` varchar(45) DEFAULT NULL,
`14` varchar(45) DEFAULT NULL,
`15` varchar(45) DEFAULT NULL,
`16` varchar(45) DEFAULT NULL,
`17` varchar(45) DEFAULT NULL,
`18` varchar(45) DEFAULT NULL,
`19` varchar(45) DEFAULT NULL,
`20` varchar(45) DEFAULT NULL,
`21` varchar(45) DEFAULT NULL,
`22` varchar(45) DEFAULT NULL,
`23` varchar(45) DEFAULT NULL,
`24` varchar(45) DEFAULT NULL,
`25` varchar(45) DEFAULT NULL,
`26` varchar(45) DEFAULT NULL,
`27` varchar(45) DEFAULT NULL,
`28` varchar(45) DEFAULT NULL,
`29` varchar(45) DEFAULT NULL,
`30` varchar(45) DEFAULT NULL,
`31` varchar(45) DEFAULT NULL,
`32` varchar(45) DEFAULT NULL,
`33` varchar(45) DEFAULT NULL,
`34` varchar(45) DEFAULT NULL,
`35` varchar(45) DEFAULT NULL,
`datetime` varchar(255) DEFAULT NULL,
PRIMARY KEY (`iddraws`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=162 ;
INSERT INTO `draws` (`iddraws`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`, `10`, `11`, `12`, `13`, `14`, `15`, `16`, `17`, `18`, `19`, `20`, `21`, `22`, `23`, `24`, `25`, `26`, `27`, `28`, `29`, `30`, `31`, `32`, `33`, `34`, `35`, `datetime`) VALUES
(1, '17', '46', '27', '30', '8', '11', '4', '40', '37', '36', '22', '14', '35', '47', '24', '20', '23', '10', '2', '42', '41', '43', '9', '19', '7', '48', '3', '38', '29', '44', '16', '12', '26', '13', '5', '1391130262'),
(2, '45', '2', '1', '24', '30', '4', '10', '11', '22', '3', '38', '33', '35', '14', '48', '28', '42', '27', '43', '9', '15', '29', '36', '41', '26', '23', '13', '5', '16', '20', '12', '6', '32', '37', '19', '1391134904'),
(3, '12', '46', '32', '15', '14', '41', '45', '6', '9', '20', '26', '2', '47', '37', '33', '39', '34', '17', '16', '23', '35', '29', '44', '36', '18', '40', '22', '4', '27', '30', '38', '21', '3', '43', '24', '1391135221');
CREATE TABLE IF NOT EXISTS `tickets` (
`id_tiketa` int(11) NOT NULL AUTO_INCREMENT,
`idtickets` varchar(45) DEFAULT NULL,
`b1` varchar(45) DEFAULT NULL,
`b2` varchar(45) DEFAULT NULL,
`b3` varchar(45) DEFAULT NULL,
`b4` varchar(45) DEFAULT NULL,
`b5` varchar(45) DEFAULT NULL,
`b6` varchar(45) DEFAULT NULL,
`shop` varchar(45) DEFAULT NULL,
`user` varchar(45) DEFAULT NULL,
`time` varchar(255) DEFAULT NULL,
`status` varchar(45) DEFAULT NULL,
`uplata` varchar(45) DEFAULT NULL,
`draw` varchar(45) DEFAULT NULL,
`qt` varchar(45) DEFAULT NULL,
`wonamount` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id_tiketa`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=138 ;
INSERT INTO `tickets` (`id_tiketa`, `idtickets`, `b1`, `b2`, `b3`, `b4`, `b5`, `b6`, `shop`, `user`, `time`, `status`, `uplata`, `draw`, `qt`, `wonamount`) VALUES
(75, '4-1-170-1367', '41', '47', '17', '24', '15', '44', '170', 'w1', '1391149398', '1', '1', '1', '', ''),
(76, '4-1-170-20104', '23', '27', '13', '7', '14', '42', '170', 'w1', '1391149398', '1', '1', '1', '', ''),
(91, '4-2-170-13887', '16', '4', '13', '35', '30', '9', '170', 'w1', '1391149462', '1', '1', '2', '', ''),
(92, '4-2-170-9701', '2', '32', '7', '15', '5', '34', '170', 'w1', '1391149463', '1', '1', '2', '', ''),
(93, '4-2-170-45661', '23', '24', '22', '27', '48', '6', '170', 'w1', '1391149463', '1', '1', '2', '', ''),
(98, '4-2-170-45503', '36', '13', '33', '10', '29', '9', '170', 'w1', '1391149463', '1', '1', '2', '', ''),
(99, '4-2-170-24095', '19', '35', '11', '36', '46', '40', '170', 'w1', '1391149463', '1', '1', '2', '', ''),
(100, '4-2-170-42832', '27', '32', '17', '29', '7', '21', '170', 'w1', '1391149463', '1', '1', '2', '', ''),
(101, '4-2-170-13570', '22', '23', '32', '6', '1', '28', '170', 'w1', '1391149463', '1', '1', '2', '', ''),
(103, '4-2-170-28122', '15', '10', '11', '9', '14', '48', '170', 'w1', '1391149463', '1', '1', '2', '', ''),
(116, '4-2-170-13095', '28', '20', '33', '42', '26', '14', '170', 'w1', '1391149464', '1', '1', '2', '', ''),
(118, '4-2-170-27646', '23', '14', '37', '27', '24', '19', '170', 'w1', '1391149464', '1', '1', '2', '', ''),
(124, '4-2-170-23302', '20', '23', '15', '38', '4', '45', '170', 'w1', '1391149465', '1', '1', '2', '', '');
SELECT t.idtickets,
t.uplata,
c.coefficient
FROM tickets t
INNER JOIN draws d ON(FIELD(t.b1,d.1,d.2,d.3,d.4,d.5,d.6,d.7,d.8,d.9,d.10,d.11,d.12,d.13,d.14,d.15,d.16,d.17,d.18,d.19,d.20,d.21,d.22,d.23,d.24,d.25,d.26,d.27,d.28,d.29,d.30,d.31,d.32,d.33,d.34,d.35)>0)
AND (FIELD(t.b2,d.1,d.2,d.3,d.4,d.5,d.6,d.7,d.8,d.9,d.10,d.11,d.12,d.13,d.14,d.15,d.16,d.17,d.18,d.19,d.20,d.21,d.22,d.23,d.24,d.25,d.26,d.27,d.28,d.29,d.30,d.31,d.32,d.33,d.34,d.35)>0)
AND (FIELD(t.b3,d.1,d.2,d.3,d.4,d.5,d.6,d.7,d.8,d.9,d.10,d.11,d.12,d.13,d.14,d.15,d.16,d.17,d.18,d.19,d.20,d.21,d.22,d.23,d.24,d.25,d.26,d.27,d.28,d.29,d.30,d.31,d.32,d.33,d.34,d.35)>0)
AND (FIELD(t.b4,d.1,d.2,d.3,d.4,d.5,d.6,d.7,d.8,d.9,d.10,d.11,d.12,d.13,d.14,d.15,d.16,d.17,d.18,d.19,d.20,d.21,d.22,d.23,d.24,d.25,d.26,d.27,d.28,d.29,d.30,d.31,d.32,d.33,d.34,d.35)>0)
AND (FIELD(t.b5,d.1,d.2,d.3,d.4,d.5,d.6,d.7,d.8,d.9,d.10,d.11,d.12,d.13,d.14,d.15,d.16,d.17,d.18,d.19,d.20,d.21,d.22,d.23,d.24,d.25,d.26,d.27,d.28,d.29,d.30,d.31,d.32,d.33,d.34,d.35)>0)
AND (FIELD(t.b6,d.1,d.2,d.3,d.4,d.5,d.6,d.7,d.8,d.9,d.10,d.11,d.12,d.13,d.14,d.15,d.16,d.17,d.18,d.19,d.20,d.21,d.22,d.23,d.24,d.25,d.26,d.27,d.28,d.29,d.30,d.31,d.32,d.33,d.34,d.35)>0)
INNER JOIN coefficients c ON c.number = GREATEST(FIELD(t.b1,d.1,d.2,d.3,d.4,d.5,d.6,d.7,d.8,d.9,d.10,d.11,d.12,d.13,d.14,d.15,d.16,d.17,d.18,d.19,d.20,d.21,d.22,d.23,d.24,d.25,d.26,d.27,d.28,d.29,d.30,d.31,d.32,d.33,d.34,d.35), FIELD(t.b2,d.1,d.2,d.3,d.4,d.5,d.6,d.7,d.8,d.9,d.10,d.11,d.12,d.13,d.14,d.15,d.16,d.17,d.18,d.19,d.20,d.21,d.22,d.23,d.24,d.25,d.26,d.27,d.28,d.29,d.30,d.31,d.32,d.33,d.34,d.35), FIELD(t.b3,d.1,d.2,d.3,d.4,d.5,d.6,d.7,d.8,d.9,d.10,d.11,d.12,d.13,d.14,d.15,d.16,d.17,d.18,d.19,d.20,d.21,d.22,d.23,d.24,d.25,d.26,d.27,d.28,d.29,d.30,d.31,d.32,d.33,d.34,d.35), FIELD(t.b4,d.1,d.2,d.3,d.4,d.5,d.6,d.7,d.8,d.9,d.10,d.11,d.12,d.13,d.14,d.15,d.16,d.17,d.18,d.19,d.20,d.21,d.22,d.23,d.24,d.25,d.26,d.27,d.28,d.29,d.30,d.31,d.32,d.33,d.34,d.35), FIELD(t.b5,d.1,d.2,d.3,d.4,d.5,d.6,d.7,d.8,d.9,d.10,d.11,d.12,d.13,d.14,d.15,d.16,d.17,d.18,d.19,d.20,d.21,d.22,d.23,d.24,d.25,d.26,d.27,d.28,d.29,d.30,d.31,d.32,d.33,d.34,d.35), FIELD(t.b6,d.1,d.2,d.3,d.4,d.5,d.6,d.7,d.8,d.9,d.10,d.11,d.12,d.13,d.14,d.15,d.16,d.17,d.18,d.19,d.20,d.21,d.22,d.23,d.24,d.25,d.26,d.27,d.28,d.29,d.30,d.31,d.32,d.33,d.34,d.35))
WHERE t.draw='1'
AND t.status = '1'
AND d.iddraws='1'
And yes, i need to do that for each t.draw and d.iddraws which will be same values.
Upvotes: 0
Views: 75
Reputation: 148
While my answer is fairly general, I am assuming you are using MySQL.
Short Answer:
Do the following things one by one in the order mentioned while measuring performance improvement with each step.
tickets.draw
and tickets.status
. Also add an index
(primary key
will be even better) on coefficients.number
.query
to stored procedure
to save values of FIELD
calls and reuse these values in GREATEST
instead of calling FIELD
again with same values.FIELD
at INSERT
/UPDATE
time instead of SELECT
. Yes, you can update all rows through query. Use your SELECT
query and make the following changes to it:
SELECT t.idtickets,t.uplata, c.coefficient FROM
by UPDATE
SET t.wonamount = c.coefficient*t.uplata, t.status='2'
before WHERE ...
(Really) Long Answer:
Your question is a very good case for discussing SQL optimization as there are many optimization techniques that can be applied here. Let me discuss them in increasing order of complexity, so that you can implement them one by one till you are happy with the results. I will also generalize every point for community's benefit while giving precise suggestions to you. Let's start:
All SQL
optimization starts with EXPLAIN
. It's a sort of black magic that tells what's wrong with your query. Simply add the EXPLAIN
keyword before the SELECT
keyword in your query and you get a wealth of information on how your query is executed behind the scene. Here is the EXPLAIN
output of your query (some fields removed for sake of brevity):
+-------+-------+---------------+---------+-------+------+-----------------+
| table | type | possible_keys | key | ref | rows | Extra |
+-------+-------+---------------+---------+-------+------+-----------------+
| d | const | PRIMARY | PRIMARY | const | 1 | |
| t | ALL | NULL | NULL | NULL | 13 | Using where |
| c | ALL | NULL | NULL | NULL | 35 | Using where;... |
+-------+-------+---------------+---------+-------+------+-----------------+
Each row covers a table
involved in your query. Two important fields to look at here are key
and rows
. rows
tells the number of rows of that table scanned for the query. The more this number, the more data MySQL
has to scan, and therefore the slower your query. key
tells if MySQL
is using any shortcut to reduce rows
. In the absence of any key
, MySQL
has to scan all rows of that table
. So, we need to supply keys
(also called indexes
) to MySQL
so that it can reduce rows
and execute queries fast.
t
(i.e. tickets
) is not using any key
and therefore scanning all rows (there are 13 rows in the sample data you provided in your fiddle, and 500,000 of them in the real data). So, we add keys
(or indexes
) to those fields of tickets
table that are involved in decision making in this query. These fields are draw
and status
(... WHERE t.draw='1' AND t.status = '1'
...).
ALTER TABLE tickets ADD INDEX idx_draw(draw);
ALTER TABLE tickets ADD INDEX idx_status(status);
coefficients
will benefit by index on number
. A PRIMARY KEY
on number
will be even better if number
s are unique.short
, int
, long
, etc.) are significantly faster than character data types (char
, varchar
, etc.). So, avoid using character data types for integer data. In your data, all fields in draws
table, and almost all fields in tickets
table contain numeric data. (Booleans can be stored as byte
instead of varchar
. Also consider storing timestamps as int
or long
instead of varchar
.)FIELD
is a costly call, especially if given a lot of arguments, as has to do a lot of work. In your query there are six distinct FIELD
calls, and each is repeated in the call to GREATEST
function, making 12 calls in total. Consider using stored procedures
which allow you to save results of function calls in variables and reuse them later.INSERT
/UPDATE
is better than performing them during SELECT
. Consider validating your tickets.b1-b6
against draws.1-35
while inserting/updating instead of querying and your SELECT
query will be much simpler and faster. The result of GREATEST
can also be calculated at insert/update time and saved in an extra field in the tickets
table to avoid recalculation every time during SELECT
.As with all queries, your query may need more optimizations when your data grows 100-1000 times its current size, but these should be enough for now.
Upvotes: 2