2

I am trying to create an event in mysql

Schema :

create event alert_2 ON SCHEDULE EVERY 300 SECOND DO 
BEGIN
DECLARE current_time DATETIME;
DECLARE attempted INT;
DECLARE completed INT;
DECLARE calc_value DECIMAL;
set @current_time = CONVERT_TZ(NOW(), @@session.time_zone, '+0:00');
select count(uniqueid) as @attempted,SUM(CASE WHEN seconds > 0 THEN 1 ELSE 0 END) as @completed from callinfo where date >= DATE_SUB(@current_time, INTERVAL 300 SECOND) AND date <= @current_time;
SET @calc_value = (ROUND((@completed/@attempted)*100,2);
IF @calc_value <= 10.00 THEN
     INSERT INTO report(value1) value (@calc_value);
END IF;
END;

Problem : Event is not going to creating

Need suggestion :

  • Is this create any overload on callinfo table ?

  • If yes,Would you like to suggest any other way to achieve same thing ?

  • May i create similar but multiple around 50.Will it create huge load on call info table.

    Call info schema :

    CREATE TABLE `callinfo` (
      `uniqueid` varchar(60) NOT NULL DEFAULT '',
      `accountid` int(11) DEFAULT '0',
      `type` tinyint(1) NOT NULL DEFAULT '0',
      `callerid` varchar(120) NOT NULL,
      `callednum` varchar(30) NOT NULL DEFAULT '',
      `seconds` smallint(6) NOT NULL DEFAULT '0',
      `trunk_id` smallint(6) NOT NULL DEFAULT '0',
      `trunkip` varchar(15) NOT NULL DEFAULT '',
      `callerip` varchar(15) NOT NULL DEFAULT '',
      `disposition` varchar(45) NOT NULL DEFAULT '',
      `date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
      `debit` decimal(20,6) NOT NULL DEFAULT '0.000000',
      `cost` decimal(20,6) NOT NULL DEFAULT '0.000000',
      `provider_id` int(11) NOT NULL DEFAULT '0',
      `pricelist_id` smallint(6) NOT NULL DEFAULT '0',
      `package_id` int(11) NOT NULL DEFAULT '0',
      `pattern` varchar(20) NOT NULL,
      `notes` varchar(80) NOT NULL,
      `invoiceid` int(11) NOT NULL DEFAULT '0',
      `rate_cost` decimal(20,6) NOT NULL DEFAULT '0.000000',
      `reseller_id` int(11) NOT NULL DEFAULT '0',
      `reseller_code` varchar(20) NOT NULL,
      `reseller_code_destination` varchar(80) DEFAULT NULL,
      `reseller_cost` decimal(20,6) NOT NULL DEFAULT '0.000000',
      `provider_code` varchar(20) NOT NULL,
      `provider_code_destination` varchar(80) NOT NULL,
      `provider_cost` decimal(20,6) NOT NULL DEFAULT '0.000000',
      `provider_call_cost` decimal(20,6) NOT NULL,
      `call_direction` enum('outbound','inbound') NOT NULL,
      `calltype` enum('STANDARD','DID','FREE','CALLINGCARD') NOT NULL DEFAULT 'STANDARD',
      `profile_start_stamp` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
      `answer_stamp` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
      `bridge_stamp` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
      `progress_stamp` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
      `progress_media_stamp` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
      `end_stamp` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
      `billmsec` int(11) NOT NULL DEFAULT '0',
      `answermsec` int(11) NOT NULL DEFAULT '0',
      `waitmsec` int(11) NOT NULL DEFAULT '0',
      `progress_mediamsec` int(11) NOT NULL DEFAULT '0',
      `flow_billmsec` int(11) NOT NULL DEFAULT '0',
      `is_recording` tinyint(1) NOT NULL DEFAULT '1' COMMENT '0 for On,1 for Off'
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='callinfo';
    ALTER TABLE `callinfo` ADD UNIQUE KEY `uniqueid` (`uniqueid`), ADD KEY `user_id` (`accountid`);
    

More Information about callinfo table :

In call info table around 20K/hour rercords are inserted. Please suggest ,If need to apply any indexing in schema to get good performance.

7
  • What's the point of the event? Commented May 10, 2018 at 20:34
  • How are you creating the event? Did you use a DELIMITER statement before creating it? Commented May 10, 2018 at 20:36
  • Running an event every 5 minutes or every 50 seconds should not overload the database, unless the query is very expensive. Commented May 10, 2018 at 20:37
  • Welcome to the StackOverflow community! Commented May 10, 2018 at 21:47
  • @Strawberry, To create an event for summary info get and pass into another table. Commented May 11, 2018 at 5:58

1 Answer 1

1

Some suggestions:

  • user-defined variables (variables named starting with @ character) are separate and distinct from local variables

  • there's no need to declare local variables that aren't referenced

  • use local variables in favor of user-defined variables

  • a column alias (identifier) that starts with @ character need to be escaped (or MySQL will throw a syntax error)

  • assigning a column alias (identifier) that looks like a user-defined variable is just a column alias; it is not a reference to a user-defined variable

  • use SELECT ... INTO to assign scalar values returned from statement into local variables and/or user-defined variables

  • declaring datatype DECIMAL is equivalent to specifying DECIMAL(10,0)

  • in INSERT ... VALUES statement the keyword is VALUES not VALUE

  • best practice is to give local variables names that are different from column names

  • best practice is to qualify all column references

  • its a bit odd to insert only a single column, a calculated value, into a table without some other identifying values (it's not illegal. it may be exactly what the specification calls for. it just strikes me as a bit odd. I bring it up in light of the code as written, because appears that the author of the code is not familiar with MySQL.)

  • using CONVERT_TZ is a bit odd; given that any datetime value referenced in a SQL statement will be interpreted in the current session time zone; we're kind of assuming that the date column is DATETIME datatype, but that's just a guess.

  • to create a MySQL stored program that contains semicolons, the DELIMITER for the session needs to be changed to character(s) that don't appear in the stored program definition


Rather than address each individual problem in the stored program, I'm going to suggest a revision that does what it looks like the original code was intended to do:

DELIMITER $$

CREATE EVENT alert_2 ON SCHEDULE EVERY 300 SECOND DO
BEGIN
   DECLARE ld_current_time DATETIME;
   DECLARE ln_calc_value   DECIMAL(20,2);
-- DECLARE li_attempted    INT;
-- DECLARE li_completed    INT;

   SET ld_current_time = CONVERT_TZ(NOW(), @@session.time_zone, '+0:00');

   SELECT ROUND( 100.0
               * SUM(CASE WHEN c.seconds > 0 THEN 1 ELSE 0 END)
               / COUNT(c.uniqueid)
          ,2) AS calc_value
 --     , COUNT(c.uniqueid) AS attempted
 --     , SUM(CASE WHEN c.seconds > 0 THEN 1 ELSE 0 END) AS completed
     FROM callinfo c
    WHERE c.date >  ld_current_time + INTERVAL -300 SECOND
      AND c.date <= ld_current_time
     INTO ln_calc_value
 --     , li_attempted
 --     , li_completed
   ;
   IF ln_calc_value <= 10.00 THEN
     INSERT INTO report ( value1 ) VALUES ( ln_calc_value );
   END IF;
END$$

DELIMITER ;

For performance, we want to have an index with date as the leading column

... ON `callinfo` (`date`, ...)

Ideally (for the query in this stored program) the index with the leading column of date would be a covering index (including all of the columns that are referenced in the query), e.g.

... ON `callinfo` (`date`,`seconds`,`uniqueid`)

Q: Is this create any overload on callinfo table ?

Since this runs a query against callinfo table, it will need to obtain shared locks. With an appropriate index available, and assuming that 5 minutes of call info is a smallish set of rows, I wouldn't expect this query to contribute significantly towards performance problems or contention issues. If it does cause a problem, I would expect that this query in this stored program isn't the root cause of the problem, it will only exacerbate a problem that already exists.

Q: If yes,Would you like to suggest any other way to achieve same thing ?

It's difficult to suggest alternatives to achieving a "thing" when we haven't defined the "thing" we are attempting to achieve.

Q: May i create similar but multiple around 50. Will it create huge load on callinfo table.

A: As long as the query is efficient, is selecting a smallish set of rows via a suitable index, and runs quickly, I wouldn't expect that query to create huge load, no.

FOLLOWUP

For optimal performance, we are definitely going to want an index with leading column of date.

I'd remove the reference to uniqueid in the query. That is, replace COUNT(c.uniqueid) with SUM(1). The results from those are equivalent (given that uniqueid is guaranteed to be non-NULL) except in the case of no rows, COUNT() will return 0 and SUM() will return NULL.

Since we're dividing by that expression, in the case of "no rows" it's a difference between "divide by zero" and "divide by null". And a "divide by zero" operation will raise an error with some settings of sql_mode. If I divide by COUNT(), I'm going to want to convert a zero to NULL before I do the division

   ... / NULLIF(COUNT(...),0)

or the more ansi standards compliant

   ... / CASE WHEN COUNT(...) = 0 THEN NULL ELSE COUNT(...) END 

but we can avoid that rigmarole by using SUM(1) instead, then we don't have any special handling for the "divide by zero" case. But what that really buys us is that we are removing the reference to the uniqueid column.

Then a "covering index" for the query will require only two columns.

... ON `callinfo` (`date`,`seconds`)

(i.e. EXPLAIN will show "Using index" in the Extra column, and show "range" for access)


Also, I'm not getting my brain wrapped around the need for CONVERT_TZ.

Sign up to request clarification or add additional context in comments.

4 Comments

I am going to add call info schema here.To get more detail information.
I just have added more information about the call info table.Please check and share more information about the table.
Thanks,Really appriciated to clear concepts about the variable declarations and its usage.
I am using convert_tz.Because my database using GMT+0 timezone in .So if client had change timezone in configs then i should not to worry about timezones.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.