MySQL使用min优化查询并限制触发器

时间:2017-08-02 03:57:48

标签: mysql database triggers

我有这个mysql查询:

SELECT MIN(v.ifr) FROM (SELECT v.ifr FROM tbl_valuation v WHERE v.stock_id = 1 ORDER BY v.created_at DESC LIMIT 19) as v;

查询说明:

+----+-------------+------------+------------+------+---------------+------------+---------+-------+------+----------+---------------------------------------+
| id | select_type | table      | partitions | type | possible_keys | key        | key_len | ref   | rows | filtered | Extra                                 |
+----+-------------+------------+------------+------+---------------+------------+---------+-------+------+----------+---------------------------------------+
|  1 | PRIMARY     | <derived2> | NULL       | ALL  | NULL          | NULL       | NULL    | NULL  |   19 |   100.00 | NULL                                  |
|  2 | DERIVED     | v          | NULL       | ref  | idx_stock     | idx_stock  | 9       | const | 2873 |   100.00 | Using index condition; Using filesort |
+----+-------------+------------+------------+------+---------------+------------+---------+-------+------+----------+---------------------------------------+

问题是,此查询和其他类似的查询都在触发器中,因此,在每次插入之前,此查询都会运行并更新某些值。 触发器每分钟激活大约一千次。

在1m记录之后,它变得越来越慢,可能是因为mysql经历了大约54587行。

有一种方法可以优化此查询吗?

这是我的触发器:

CREATE TRIGGER BUY_WARNING_TRIG BEFORE INSERT 
ON tbl_valuation
FOR EACH ROW
BEGIN
    DECLARE warn_counter INT DEFAULT 0;
    DECLARE min_ifr DECIMAL(17,12);
    DECLARE min_lgui DECIMAL(17,12);
    DECLARE stock VARCHAR(100);    

    IF New.ls >= New.macd THEN
        SELECT MIN(v.ifr) 
            FROM (SELECT v.ifr FROM tbl_valuation v WHERE v.stock_id = New.stock_id ORDER BY v.created_at DESC LIMIT 9) as v INTO min_ifr;

        IF New.ifr <= min_ifr THEN
            SELECT MIN(v.lgui) 
                FROM (SELECT v.lgui FROM tbl_valuation v WHERE v.stock_id = New.stock_id ORDER BY v.created_at DESC LIMIT 9) as v INTO min_lgui;

            IF New.lgui <= min_lgui THEN
                SET warn_counter = warn_counter + 1;
            END IF;
        END IF;

        SELECT MIN(v.ifr) FROM (SELECT v.ifr FROM tbl_valuation v WHERE v.stock_id = New.stock_id ORDER BY v.created_at DESC LIMIT 4) as v INTO min_ifr;

        IF New.ifr <= min_ifr THEN
            SELECT MIN(v.lgui) 
                    FROM (SELECT v.lgui FROM tbl_valuation v WHERE v.stock_id = New.stock_id ORDER BY v.created_at DESC LIMIT 4) as v INTO min_lgui;

            IF New.lgui <= min_lgui THEN
                SET warn_counter = warn_counter + 1;
            END IF;
        END IF;

        SELECT MIN(v.ifr) FROM (SELECT v.ifr FROM tbl_valuation v WHERE v.stock_id = New.stock_id ORDER BY v.created_at DESC LIMIT 19) as v INTO min_ifr;

        IF New.ifr <= min_ifr THEN
            SELECT MIN(v.lgui) 
                    FROM (SELECT v.lgui FROM tbl_valuation v WHERE v.stock_id = New.stock_id ORDER BY v.created_at DESC LIMIT 19) as v INTO min_lgui;

            IF New.lgui <= min_lgui THEN
                SET warn_counter = warn_counter + 1;
            END IF;
        END IF;
    END IF;

    IF warn_counter > 0 THEN
        SELECT t.stock FROM tbl_stock t WHERE t.id = New.stock_id INTO stock;
        CASE warn_counter
            WHEN 1 THEN INSERT INTO tbl_warning (created_at, stock, level, rate, `type`) VALUES (NOW(), stock, 'LOW', New.rate, 'BUY');
            WHEN 2 THEN INSERT INTO tbl_warning (created_at, stock, level, rate, `type`) VALUES (NOW(), stock, 'MED', New.rate, 'BUY');
            WHEN 3 THEN INSERT INTO tbl_warning (created_at, stock, level, rate, `type`) VALUES (NOW(), stock, 'HIGH', New.rate, 'BUY');
        END CASE;
    END IF;
END$$

1 个答案:

答案 0 :(得分:2)

您的查询绝对需要支持TreeSet - 条件和tbl_valuation (stock_id, created_at)的索引where(按此顺序)。这将摆脱order by

为了加快速度,您应该在查询中使用另外两列Using filesort,以使其成为覆盖索引。这将节省在表格中查找这些值的时间(并将显示为tbl_valuation (stock_id, created_at, ifr, lgui))。

由于您基本上执行了非常类似的查询6次,因此您的触发器代码本身也可能通过重新组织或使用不同的方法进行优化,尽管我不打算这样做。一个快速优化:通过组合using indexlgui的查询,您可以将查询数量减少一半:

ifr

任何时候都不会花费你这么做,所以如果你不需要 SELECT min(v.ifr), min(v.lgui) into min_ifr, min_lgui FROM (SELECT v.ifr, v.lgui FROM tbl_valuation v WHERE v.stock_id = new.stock_id ORDER BY v.created_at DESC LIMIT 9) as v - 值,那么就没有任何伤害,但是如果你确实需要,那么你保存一个min_lgui