MySQL不一致查询导致临时表(空结果集)的过程

时间:2017-04-12 07:51:58

标签: mysql stored-procedures mariadb temp-tables

我也在dba.stackexchange上发布了这个问题,但我也把它放在这里,希望得到更多答案。

我们的服务器在AWS EC2实例上运行10.0.30-MariaDB。我们有一个存储过程,它创建多个临时表,它们之间的连接,最终产生最终结果。当我们第一次调用此过程时(在新连接中),我们总是得到一个结果。如果我们再次调用此过程,但使用不同的参数,则该连接的结果集始终为空。如果我们启动一个新连接并再次进行第二次调用,那么此调用将返回正确的结果,但第一次调用将为空。请参阅下面的简化方案:

Connection 1:
call my_procedure("a"); > 1 row returned
call my_procedure("b"); > 0 rows returned
call my_procedure("a"); > 1 row returned

Connection 2:
call my_procedure("b"); > 1 row returned
call my_procedure("a"); > 0 rows returned
call my_procedure("b"); > 1 row returned

我们总能以这种方式重现这种行为。

此外,当我们更改过程时(即使只添加注释),下一个调用就像在新连接上调用一样。因此,如果我们首先打电话给" a",我们会得到结果,但是" b"永远不会工作,反之亦然。

我们的程序是有效的sql并返回正确的数据,临时表被正确清除,......但由于某种原因在某些情况下不返回数据。

我们得到的印象是我们遇到了一些内部限制'或者。我们已经尝试了各种各样的东西,但我们已经没有选择在哪里查看或如何调试。

欢迎任何有关如何调试此类情况的建议。

请参阅下面的程序。我把它简化了一下。在dba.stackexchange帖子上,您可以看到另一个完整版本:

PROCEDURE `select_products`(IN arg_uuid VARCHAR(36),
                            IN arg_application VARCHAR(36),
                            IN arg_app_version VARCHAR(20),
                            IN arg_installation VARCHAR(50),
                            IN arg_user VARCHAR(36),
                            IN arg_product VARCHAR(36),
                            IN arg_license VARCHAR(36),
                            IN arg_type VARCHAR(10),
                            IN arg_code VARCHAR(255),
                            IN arg_group VARCHAR(100))
BEGIN

  DECLARE var_b_user INT DEFAULT NULL; 

  SET var_b_user = (select bu.id from b_user bu JOIN user u on u.id = bu.user where u.`key` = arg_user limit 1);


  /********************* PLTA **********************/

  DROP TEMPORARY TABLE IF EXISTS plta;
  CREATE TEMPORARY TABLE plta (product_id INT, license_id INT, token_id INT, activation_id INT, INDEX(product_id, license_id))
  SELECT
    l.product as product_id, l.id as license_id, lt.token as token_id, null as activation_id
  FROM
    license l,
    license_token lt,
    activation a,
    `user` u
  WHERE
        a.current = TRUE
    AND l.id = lt.license
    AND a.`user` = u.id
    AND a.installation = arg_installation
    AND u.`key` = arg_user
    AND lt.token = a.token
    group by product_id, license_id, token_id;

    UPDATE plta, activation a, `user` u
    SET activation_id = a.id
    WHERE
        u.id = a.user
    and a.current = TRUE
    AND u.`key` = arg_user
    AND a.installation = arg_installation
    AND a.license = plta.license_id
    AND a.token = plta.token_id;


  /********************* TMP_PP **********************/

  DROP TEMPORARY TABLE IF EXISTS tmp_pp;
  CREATE TEMPORARY TABLE tmp_pp (product INT,INDEX(product))
  SELECT DISTINCT
    p.id AS product
  FROM
    product p
  JOIN
    application n
  ON
       p.application = n.id
   AND n.`key` = arg_application
  LEFT JOIN
    (
      SELECT
        gp.product
      FROM
        product_group__product gp,
        product_group g
      WHERE
            gp.enabled = TRUE
        AND gp.product_group = g.id
        AND g.`key` = arg_group
     ) g
   ON
     p.id = g.product

  WHERE
        (   p.`key` = arg_product
         OR (    arg_product IS NULL
             AND p.enabled = TRUE))
    AND (   g.product IS NOT NULL
         OR arg_group IS NULL)
    AND (   p.app_version IS NULL
         OR arg_app_version IS NULL
         OR (INET_ATON(p.app_version) <= INET_ATON(arg_app_version)));

  select * from tmp_pp;


  /********************* TMP_LT **********************/

  DROP TEMPORARY TABLE IF EXISTS tmp_lt;
  CREATE TEMPORARY TABLE tmp_lt (license INT,token INT,INDEX(license),INDEX(token))
    SELECT
      lt.license,
      t.id as token
    FROM
      license_token lt,
      token t
    WHERE
          lt.token = t.id
      AND t.`type` = arg_type
      AND (  (    arg_code IS NOT NULL
              AND t.code = arg_code)
           OR arg_type = 'free');


  select * from tmp_lt;


  /********************* PLT_PROD **********************/

  SELECT
    p.id AS product,
    l.id AS license,
    tmp_lt.token,
    NULL AS activation,
    FALSE AS license_auto_activation
  FROM
    product p
  JOIN
    tmp_pp
  ON
    p.id = tmp_pp.product
  JOIN
    license l
  ON
        (   l.`key` = arg_license 
         OR arg_license IS NULL)
    AND l.enabled = TRUE
    AND l.product = p.id
    AND (   l.app_version IS NULL
         OR arg_app_version IS NULL
         OR (INET_ATON(l.app_version) <= INET_ATON(arg_app_version))) 
  LEFT JOIN
    tmp_lt
  ON
    l.id = tmp_lt.license  
  WHERE
     (   arg_type IS NULL
         OR arg_type = 'auto'
         OR tmp_lt.token IS NOT NULL);

END

另外&#39;有趣&#39;需要注意的是,如果我们将最后一个WHERE更改为WHERE arg_type = 'auto';,则不会发生这种问题(尽管结果当然不一样)。

0 个答案:

没有答案