加快自定义DATE_BETWEEN功能

时间:2017-02-07 12:33:39

标签: mysql csv datetime

下面的函数(+用法示例)实现了一些我需要在一个相当复杂的select查询中使用的业务逻辑,它已经将我们的数据库服务器推向了它的极限。下面的代码(复制/粘贴;-)使用2选项CSV运行大约35毫秒(没有删除和创建);我需要加快速度......

它的作用

在endDate之前从CSV选项中给我一个更晚的startDate,或者 - 当endDate无效时 - 在startDate之后。

DROP FUNCTION IF EXISTS later_start_before_end_date;
delimiter $$
CREATE FUNCTION later_start_before_end_date(startDate DATETIME, endDate DATETIME, optionsCSV CHAR(255)) 
RETURNS DATETIME
-- COMMENT "Choose the latest alternative start-datetime from a comma-separated optionsCSV of UNIX timestamps that is inbetween startDate DATETIME and endDate DATE"
-- COMMENT "endDate value of NULL will be interpreted as INDEFINITE"
BEGIN
--  SET @optionsCSV = CONCAT(optionDate1, ',', optionDate2); -- e.g. "2002-10-10 02:01:00,2005-10-10 23:21:00"
    SET @isIndefiniteEnd = (ISNULL(endDate) OR endDate LIKE("0000-00-00%"));
    SET @returnValue = startDate;

    WHILE (NOT ISNULL(optionsCSV) AND (optionsCSV) != '') DO
        SET @strLen = LENGTH(optionsCSV);
        SET @altDate = STR_TO_DATE(SUBSTRING_INDEX(optionsCSV, ',', 1), '%Y-%m-%d %H:%i:%s');
        SET @isAfterNewStart = (TIMESTAMPDIFF(SECOND, @returnValue, @altDate) > 0);

        CASE (@isAfterNewStart) 
        WHEN 1 THEN 
            SET @isBeforeEnd = (NOT @isIndefiniteEnd /* timestampdiff cannot calculate null or zero date! */
                    AND TIMESTAMPDIFF(SECOND, endDate, @altDate) < 0);

            CASE (@isIndefiniteEnd OR @isBeforeEnd)
            WHEN 1 THEN 
                SET @returnValue = @altDate;
            ELSE BEGIN END;
            END CASE;

        ELSE BEGIN END;
        END CASE;

        SET @subStrLen = LENGTH(SUBSTRING_INDEX(optionsCSV, ',', 1));
        SET optionsCSV = MID(optionsCSV, @subStrLen+2, @strLen);

    END WHILE;

    RETURN @returnValue;

END; $$
delimiter ;

/* Use it ... */
SET @startDate = STR_TO_DATE('2002-10-10 00:00:00', '%Y-%m-%d %H:%i:%s');
SET @endDate  = STR_TO_DATE('2003-10-10', '%Y-%m-%d');
/* ... edge cases for the above start-end */
SET @optionsCSV = CONCAT(
--  TIMESTAMP('2002-10-10 00:00:00'),
--  ',', 
--  TIMESTAMP('2002-10-10 00:00:01'),
--  ',', 
    TIMESTAMP('2003-10-10 00:00:00'),
    ',', 
    TIMESTAMP('2003-10-09 23:59:59')
    );
/* ... or a single timestamp */
-- SET @optionsCSV = TIMESTAMP('2002-10-10 00:00:01');
SELECT later_start_before_end_date(@startDate, @endDate, @optionsCSV);

目标和注意事项

  • 我正在寻找能够在小于10毫秒中运行上述代码的改进。
  • 我在一个公司遗留的MySQL数据库(5.1.73)中工作,这个数据库多年来在我需要访问的表中使用各种日期时间类型(DATETIME,DATE)和TIMESTAMP)...类型更改是不可接受的,
  • 我希望该功能只有一个选项参数,以便在其他可能的用例中具有更大的灵活性。
  • 日期格式中的多个选项(startDate,endDate,option1 TIMESTAMP,option2 DATETIME,...)可能是可接受的,如果它非常显着提高性能。

任何建议都受到高度赞赏。

0 个答案:

没有答案