优化查询mysql

时间:2014-01-31 05:44:12

标签: mysql

我有3个表,其中存储了一些值。一切都工作正常,但我的查询执行时间太长。目前我在表“门票”中有大约500,000行。我想知道什么是优化此查询以更快地执行SELECT的最佳方法。

还有一件事:我想知道有没有办法通过查询更新所有行(不使用我的C#应用​​程序)。在这种情况下,我需要通过将行“系数”与行“uplata”相乘并使用值“2”更新列状态来更新具有值的票证中的“wonamount”列。

这是我的表和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'

是的,我需要为每个t.draw和d.iddraws做同样的值。

2 个答案:

答案 0 :(得分:2)

虽然我的答案相当笼统,但我假设您使用的是MySQL。

简答:
在测量每个步骤的性能改进时,按照上述顺序逐一执行以下操作。

  1. tickets.drawtickets.status上添加索引。另外在index上添加primary keycoefficients.number会更好)。
  2. 尽可能使用int而不是varchar。
  3. query转换为stored procedure以保存FIELD个来电的值,并在GREATEST中重复使用这些值,而不是再次使用相同的值调用FIELD
  4. FIELD / INSERT时间而不是UPDATE将呼叫转移到SELECT
  5. 是的,您可以通过查询更新所有行。使用您的SELECT查询并对其进行以下更改:

    1. SELECT t.idtickets,t.uplata, c.coefficient FROM替换为UPDATE
    2. SET t.wonamount = c.coefficient*t.uplata, t.status='2'
    3. 之前添加WHERE ...

      (真)长答案:
      您的问题是讨论SQL优化的一个非常好的案例,因为这里可以应用许多优化技术。让我以增加复杂度的顺序来讨论它们,这样你就可以逐个实现它们,直到你对结果满意为止。我还将为社区的利益概括每一点,同时向您提供准确的建议。让我们开始吧:

      1. 所有SQL优化均以EXPLAIN开头。这是一种黑魔法,可以告诉您查询的错误。只需在查询中的EXPLAIN关键字之前添加SELECT关键字,即可获得有关如何在场景后执行查询的大量信息。以下是查询的EXPLAIN输出(为简洁起见,删除了一些字段):

        +-------+-------+---------------+---------+-------+------+-----------------+    
        | 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;... |    
        +-------+-------+---------------+---------+-------+------+-----------------+    
        

        每行包含查询中涉及的table。要在此处查看的两个重要字段是keyrowsrows表示为查询扫描的该表的行数。此数字越多,数据MySQL必须扫描的次数越多,因此查询速度越慢。 key告知MySQL是否正在使用任何缩写rows。如果没有任何key,则MySQL必须扫描table的所有行。因此,我们需要向keys提供indexes(也称为MySQL),以便它可以减少rows并快速执行查询。

        • 此处,表t(即tickets)未使用任何key,因此扫描所有行(您在小提琴中提供的示例数据中有13行,以及500,000行)他们在真实的数据中)。因此,我们将keys(或indexes}添加到tickets表中参与此查询决策的字段中。这些字段为drawstatus(... WHERE t.draw='1' AND t.status = '1' ...)。
          • MySQL的> ALTER TABLE tickets ADD INDEX idx_draw(draw);
          • MySQL的> ALTER TABLE tickets ADD INDEX idx_status(status);
        • 同样,coefficients将受益于number的索引。如果PRIMARY KEY是唯一的,number上的number会更好。
      2. 整数数据类型(shortintlong等)明显快于字符数据类型(charvarchar等。 )。因此,避免对整数数据使用字符数据类型。在您的数据中,draws表中的所有字段以及tickets表中的几乎所有字段都包含数字数据。 (布尔值可以存储为byte而不是varchar。还可以考虑将时间戳存储为intlong而不是varchar。)
      3. FIELD是一个代价高昂的电话,特别是如果有很多论据的话,就像做了很多工作一样。在您的查询中,有六个不同的FIELD调用,每个调用都在GREATEST函数的调用中重复,共调用12个调用。考虑使用stored procedures,它允许您将函数调用的结果保存在变量中,并在以后重用它们。
      4. INSERT / UPDATE期间执行验证优于在SELECT期间执行验证。在插入/更新而不是查询时,请考虑针对tickets.b1-b6验证draws.1-35,并且您的SELECT查询会更加简单快捷。 GREATEST的结果也可以在插入/更新时计算并保存在tickets表的额外字段中,以避免每次SELECT期间重新计算。
      5. 与所有查询一样,当您的数据增长到当前大小的100-1000倍时,您的查询可能需要更多优化,但现在这些应该足够了。

答案 1 :(得分:1)

你的数据库有索引吗? MYSQL indexes