create event of mysql with some logic not working - mysql

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.

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.

Related

Speed Up A Large Insert From Select Query With Multiple Joins

I'm trying to denormalize a few MySQL tables I have into a new table that I can use to speed up some complex queries with lots of business logic. The problem that I'm having is that there are 2.3 million records I need to add to the new table and to do that I need to pull data from several tables and do a few conversions too. Here's my query (with names changed)
INSERT INTO database_name.log_set_logs
(offload_date, vehicle, jurisdiction, baselog_path, path,
baselog_index_guid, new_location, log_set_name, index_guid)
(
select STR_TO_DATE(logset_logs.offload_date, '%Y.%m.%d') as offload_date,
logset_logs.vehicle, jurisdiction, baselog_path, path,
baselog_trees.baselog_index_guid, new_location, logset_logs.log_set_name,
logset_logs.index_guid
from
(
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(path, '/', 7), '/', -1) as offload_date,
SUBSTRING_INDEX(SUBSTRING_INDEX(path, '/', 8), '/', -1) as vehicle,
SUBSTRING_INDEX(path, '/', 9) as baselog_path, index_guid,
path, log_set_name
FROM database_name.baselog_and_amendment_guid_to_path_mappings
) logset_logs
left join database_name.log_trees baselog_trees
ON baselog_trees.original_location = logset_logs.baselog_path
left join database_name.baselog_offload_location location
ON location.baselog_index_guid = baselog_trees.baselog_index_guid);
The query itself works because I was able to run it using a filter on log_set_name however that filter's condition will only work for less than 1% of the total records because one of the values for log_set_name has 2.2 million records in it which is the majority of the records. So there is nothing else I can use to break this query up into smaller chunks from what I can see. The problem is that the query is taking too long to run on the rest of the 2.2 million records and it ends up timing out after a few hours and then the transaction is rolled back and nothing is added to the new table for the 2.2 million records; only the 0.1 million records were able to be processed and that was because I could add a filter that said where log_set_name != 'value with the 2.2 million records'.
Is there a way to make this query more performant? Am I trying to do too many joins at once and perhaps I should populate the row's columns in their own individual queries? Or is there some way I can page this type of query so that MySQL executes it in batches? I already got rid of all my indexes on the log_set_logs table because I read that those will slow down inserts. I also jacked my RDS instance up to a db.r4.4xlarge write node. I am also using MySQL Workbench so I increased all of it's timeout values to their maximums giving them all nines. All three of these steps helped and were necessary in order for me to get the 1% of the records into the new table but it still wasn't enough to get the 2.2 million records without timing out. Appreciate any insights as I'm not adept to this type of bulk insert from a select.
'CREATE TABLE `log_set_logs` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`purged` tinyint(1) NOT NULL DEFAUL,
`baselog_path` text,
`baselog_index_guid` varchar(36) DEFAULT NULL,
`new_location` text,
`offload_date` date NOT NULL,
`jurisdiction` varchar(20) DEFAULT NULL,
`vehicle` varchar(20) DEFAULT NULL,
`index_guid` varchar(36) NOT NULL,
`path` text NOT NULL,
`log_set_name` varchar(60) NOT NULL,
`protected_by_retention_condition_1` tinyint(1) NOT NULL DEFAULT ''1'',
`protected_by_retention_condition_2` tinyint(1) NOT NULL DEFAULT ''1'',
`protected_by_retention_condition_3` tinyint(1) NOT NULL DEFAULT ''1'',
`protected_by_retention_condition_4` tinyint(1) NOT NULL DEFAULT ''1'',
`general_comments_about_this_log` text,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1736707 DEFAULT CHARSET=latin1'
'CREATE TABLE `baselog_and_amendment_guid_to_path_mappings` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`path` text NOT NULL,
`index_guid` varchar(36) NOT NULL,
`log_set_name` varchar(60) NOT NULL,
PRIMARY KEY (`id`),
KEY `log_set_name_index` (`log_set_name`),
KEY `path_index` (`path`(42))
) ENGINE=InnoDB AUTO_INCREMENT=2387821 DEFAULT CHARSET=latin1'
...
'CREATE TABLE `baselog_offload_location` (
`baselog_index_guid` varchar(36) NOT NULL,
`jurisdiction` varchar(20) NOT NULL,
KEY `baselog_index` (`baselog_index_guid`),
KEY `jurisdiction` (`jurisdiction`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1'
'CREATE TABLE `log_trees` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`baselog_index_guid` varchar(36) DEFAULT NULL,
`original_location` text NOT NULL, -- This is what I have to join everything on and since it's text I cannot index it and the largest value is above 255 characters so I cannot change it to a vachar then index it either.
`new_location` text,
`distcp_returncode` int(11) DEFAULT NULL,
`distcp_job_id` text,
`distcp_stdout` text,
`distcp_stderr` text,
`validation_attempt` int(11) NOT NULL DEFAULT ''0'',
`validation_result` tinyint(1) NOT NULL DEFAULT ''0'',
`archived` tinyint(1) NOT NULL DEFAULT ''0'',
`archived_at` timestamp NULL DEFAULT NULL,
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`dir_exists` tinyint(1) NOT NULL DEFAULT ''0'',
`random_guid` tinyint(1) NOT NULL DEFAULT ''0'',
`offload_date` date NOT NULL,
`vehicle` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `baselog_index_guid` (`baselog_index_guid`)
) ENGINE=InnoDB AUTO_INCREMENT=1028617 DEFAULT CHARSET=latin1'
baselog_offload_location has not PRIMARY KEY; what's up?
GUIDs/UUIDs can be terribly inefficient. A partial solution is to convert them to BINARY(16) to shrink them. More details here: http://localhost/rjweb/mysql/doc.php/uuid ; (MySQL 8.0 has similar functions.)
It would probably be more efficient if you have a separate (optionally redundant) column for vehicle rather than needing to do
SUBSTRING_INDEX(SUBSTRING_INDEX(path, '/', 8), '/', -1) as vehicle
Why JOIN baselog_offload_location? Three seems to be no reference to columns in that table. If there, be sure to qualify them so we know what is where. Preferably use short aliases.
The lack of an index on baselog_index_guid may be critical to performance.
Please provide EXPLAIN SELECT ... for the SELECT in your INSERT and for the original (slow) query.
SELECT MAX(LENGTH(original_location)) FROM .. -- to see if it really is too big to index. What version of MySQL are you using? The limit increased recently.
For the above item, we can talk about having a 'hash'.
"paging the query". I call it "chunking". See http://mysql.rjweb.org/doc.php/deletebig#deleting_in_chunks . That talks about deleting, but it can be adapted to INSERT .. SELECT since you want to "chunk" the select. If you go with chunking, Javier's comment becomes moot. Your code would be chunking the selects, hence batching the inserts:
Loop:
INSERT .. SELECT .. -- of up to 1000 rows (see link)
End loop

How to improve the performance of this query Sql in MySql?

I have a query in SQL that takes about 15 seconds to return the result, I need to improve the performance, I've worked a few hours and I can't get a satisfactory result.
MySql 5.6
Table lote: 304053 rows
Table Prod_lista: 41525 rows
Time result: 15 Seconds
SET #CODIGO_EMPRESA = 1;
SET #CODIGO_FILIAL = 1;
SET #PESQUISA = '%';
SELECT
B.CODIGO_PRODUTO,
C.DESCRICAO,
B.SALDO_DISPONIVEL,
B.SALDO_RESERVADO,
B.SALDO_INDISPONIVEL,
B.SALDO_TERCEIROS,
B.SALDO_ENTREGUE,
C.SITUACAO
FROM
(SELECT
A.CODIGO_EMPRESA,
A.CODIGO_FILIAL,
A.CODIGO_PRODUTO,
SUM(A.SALDO_DISPONIVEL) AS SALDO_DISPONIVEL,
SUM(A.SALDO_RESERVADO) AS SALDO_RESERVADO,
SUM(A.SALDO_INDISPONIVEL) AS SALDO_INDISPONIVEL,
SUM(A.SALDO_TERCEIROS) AS SALDO_TERCEIROS,
SUM(A.SALDO_ENTREGUE) AS SALDO_ENTREGUE
FROM
LOTE A
WHERE
A.CODIGO_EMPRESA = #CODIGO_EMPRESA
AND A.CODIGO_FILIAL = #CODIGO_FILIAL
AND IFNULL(A.ENCERRADO, 0) = 0
AND A.TIPO NOT IN (4 , 5)
GROUP BY A.CODIGO_PRODUTO
ORDER BY NULL) B
INNER JOIN
PROD_LISTA C ON B.CODIGO_EMPRESA = C.CODIGO_EMPRESA
AND B.CODIGO_FILIAL = C.CODIGO_FILIAL
AND B.CODIGO_PRODUTO = C.CODIGO
AND IFNULL(C.SITUACAO, 1) = 1
WHERE
(B.CODIGO_PRODUTO LIKE #PESQUISA
OR C.CODIGOFABRICA LIKE #PESQUISA
OR C.CODIGOBARRA_COMPLETO LIKE #PESQUISA
OR C.DESCRICAO LIKE #PESQUISA
OR EXISTS( SELECT
D.CODIGOPRODUTO
FROM
PROD_CODIGO_BARRA D
WHERE
D.CODIGO_EMPRESA = #CODIGO_EMPRESA
AND D.CODIGO_FILIAL = #CODIGO_FILIAL
AND B.CODIGO_PRODUTO = D.CODIGOPRODUTO
AND D.CODIGOBARRA_COMPLETO LIKE #PESQUISA))
LIMIT 0 , 100
Structure of the batch table
CREATE TABLE `lote` (
`CODIGO_EMPRESA` int(3) unsigned NOT NULL,
`CODIGO_FILIAL` int(4) unsigned NOT NULL,
`CODIGO_LOTE` bigint(20) NOT NULL,
`CODIGO_LOTE_PAI` bigint(20) DEFAULT NULL,
`NUMERO_LOTE` varchar(15) DEFAULT NULL,
`TIPO` int(2) DEFAULT NULL ,
`DATAHORA` datetime DEFAULT NULL,
`CODIGO_DOCUMENTO` bigint(20) DEFAULT NULL,
`CODIGO_ITEM` int(5) DEFAULT NULL,
`CUSTO` decimal(21,10) DEFAULT '0.0000000000',
`CODIGO_PRODUTO` varchar(25) DEFAULT NULL,
`DESTINO_INICIAL` int(1) DEFAULT NULL,
`SALDO_INICIAL` decimal(15,4) DEFAULT '0.0000',
`SALDO_DISPONIVEL` decimal(15,4) DEFAULT '0.0000',
`SALDO_INDISPONIVEL` decimal(15,4) DEFAULT '0.0000',
`SALDO_TERCEIROS` decimal(15,4) DEFAULT '0.0000',
`SALDO_RESERVADO` decimal(15,4) DEFAULT '0.0000',
`SALDO_ENTREGUE` decimal(15,4) DEFAULT '0.0000',
`VENCIMENTO` date DEFAULT NULL,
`ENCERRADO` int(1) DEFAULT '0',
`CODIGO_CONTAGEM` bigint(11) unsigned DEFAULT NULL,
PRIMARY KEY (`CODIGO_EMPRESA`,`CODIGO_FILIAL`,`CODIGO_LOTE`),
KEY `IDX_CODIGO_LOTE` (`CODIGO_LOTE`),
KEY `IDX_CODIGO_PRODUTO` (`CODIGO_EMPRESA`,`CODIGO_FILIAL`,`CODIGO_PRODUTO`),
KEY `IDX_CONSULTA_PDV` (`CODIGO_EMPRESA`,`CODIGO_FILIAL`,`CODIGO_PRODUTO`,`ENCERRADO`,`TIPO`),
KEY `IDX_CONTAGEM_ESTOQUE` (`CODIGO_EMPRESA`,`CODIGO_FILIAL`,`CODIGO_PRODUTO`,`TIPO`,`ENCERRADO`),
KEY `IDX_CUSTO` (`CODIGO_EMPRESA`,`CODIGO_FILIAL`,`CUSTO`),
KEY `IDX_DOCUMENTO_ITEM` (`CODIGO_EMPRESA`,`CODIGO_FILIAL`,`CODIGO_DOCUMENTO`,`CODIGO_ITEM`),
KEY `IDX_EMPRESA_FILIAL` (`CODIGO_EMPRESA`,`CODIGO_FILIAL`),
KEY `IDX_ESTOQUE` (`CODIGO_EMPRESA`,`CODIGO_FILIAL`,`TIPO`,`ENCERRADO`),
KEY `IDX_FILTRO` (`CODIGO_EMPRESA`,`CODIGO_FILIAL`,`CODIGO_LOTE`,`DATAHORA`),
KEY `IDX_LOTE_COMP` (`CODIGO_EMPRESA`,`CODIGO_FILIAL`,`CODIGO_PRODUTO`,`DATAHORA`),
KEY `IDX_TIPO` (`TIPO`),
KEY `IDX_TIPO_CODIGO` (`CODIGO_EMPRESA`,`CODIGO_FILIAL`,`TIPO`,`CODIGO_PRODUTO`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
How can I improve SQL to have a faster result?
OR is a performance killer; try to avoid it.
B.CODIGO_PRODUTO LIKE "%" is equivalent to TRUE, but the Optimizer does not see that. It would be much better to construct the query dynamically instead of using #variables and picking values that eliminate clauses.
Also of importance is that the Optimizer may be able to use an index when there is not a leading wildcard:
x LIKE 'A%' -- possibly uses index
x LIKE '%' -- cannot use index
x LIKE '%B' -- cannot use index
x LIKE '#foo' -- cannot use index
int(4) -- the (4) is irrelevant. All INTs are the same 4-byte datatype. See SMALLINT and similar ones for smaller datatypes.
Don't blindly use NULL (most of your columns are NULLable); leave NULL for optional / unknown / etc, values.
IFNULL(A.ENCERRADO, 0) = 0 -- If you can arrange for this to have 2 values (0 and 1), you can simplify this expression and avoid using a function. Functions make expressions not 'sargable'. Once you have done that, the suggested index below may be useful.
When you have INDEX(a,b,c), there is no need for also having INDEX(a,b). For example: IDX_EMPRESA_FILIAL can be dropped.
These indexes may help:
D: (CODIGOPRODUTO, CODIGO_FILIAL, CODIGO_EMPRESA, CODIGOBARRA_COMPLETO)
A: (ENCERRADO, CODIGO_FILIAL, TIPO, CODIGO_EMPRESA)
There may be more suggestions. Apply most of the above, then come back for more suggestions. (And provide the other SHOW CREATE TABLEs.)
Correlated subqueries, like your EXISTS one, can be costly if they are correlated with a large number of results from the outer query. I'd suggest converting your EXISTS condition into something like this:
OR B.CODIGO_PRODUTO IN (
SELECT D.CODIGOPRODUTO
FROM PROD_CODIGO_BARRA AS D
WHERE D.CODIGO_EMPRESA = #CODIGO_EMPRESA
AND D.CODIGO_FILIAL = #CODIGO_FILIAL
AND D.CODIGOBARRA_COMPLETO LIKE #PESQUISA
)
With your correlated version, the subquery ends up being evaluated separately for every row coming out of the main FROM. But with this non-correlated version, the subquery is only evaluated once, and it's result set is used to check the rows coming out of the main FROM.

Why does this fail on some MySQL installs and not on other MySQL/MariaDB installs

FINAL: I'm closing this question because there is no way for me to reproduce the condition and trying to find a similar occurrence has proven fruitless.
A work-around using perl is being implemented to circumvent the failure that only some mysql installs are experiencing.
UPDATE: I've had another case and verified that this query is returning 'OFF'
SELECT `VARIABLE_VALUE` FROM `information_schema`.`GLOBAL_VARIABLES` WHERE `VARIABLE_NAME` LIKE 'INNODB_STRICT_MODE'
I'm having a hard time tracking down a query issue...
This is part of an update script that I made to install new tables and import data from old ones - if they exist. This is from a procedure that is installed, and then called, by the update script:
In this snippet, the table bot_inventories is created, then a check is performed to see if the old schema table exists. If it does, the old 'base' data is then copied to the new table.
The suspect query is the 'inner' if near the bottom:
CREATE TABLE `bot_inventories` (
`inventories_index` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
`bot_id` INT(11) UNSIGNED NOT NULL DEFAULT '0',
`slot_id` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0',
`item_id` INT(11) UNSIGNED NULL DEFAULT '0',
`inst_charges` TINYINT(3) UNSIGNED DEFAULT 0,
`inst_color` INT(11) UNSIGNED NOT NULL DEFAULT '0',
`inst_no_drop` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0',
`inst_custom_data` TEXT NULL,
`ornament_icon` INT(11) UNSIGNED NOT NULL DEFAULT '0',
`ornament_id_file` INT(11) UNSIGNED NOT NULL DEFAULT '0',
`ornament_hero_model` INT(11) NOT NULL DEFAULT '0',
`augment_1` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0',
`augment_2` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0',
`augment_3` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0',
`augment_4` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0',
`augment_5` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0',
`augment_6` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0',
PRIMARY KEY (`inventories_index`),
KEY `FK_bot_inventories_1` (`bot_id`),
CONSTRAINT `FK_bot_inventories_1` FOREIGN KEY (`bot_id`) REFERENCES `bot_data` (`bot_id`)
) ENGINE=InnoDB;
IF ((SELECT COUNT(*) FROM `information_schema`.`TABLES` WHERE `TABLE_SCHEMA` = DATABASE() AND `TABLE_NAME` = 'botinventory') > 0) THEN
INSERT INTO `bot_inventories` (
`inventories_index`,
`bot_id`,
`slot_id`,
`item_id`,
`inst_charges`,
`inst_color`,
`inst_no_drop`,
`augment_1`,
`augment_2`,
`augment_3`,
`augment_4`,
`augment_5`
)
SELECT
bi.`BotInventoryID`,
bi.`BotID`,
bi.`SlotID`,
bi.`ItemID`,
bi.`charges`,
bi.`color`,
bi.`instnodrop`,
bi.`augslot1`,
bi.`augslot2`,
bi.`augslot3`,
bi.`augslot4`,
bi.`augslot5`
FROM `botinventory` bi
INNER JOIN `bot_data` bd
ON bi.`BotID` = bd.`bot_id`;
IF ((SELECT COUNT(*) FROM `information_schema`.`COLUMNS` WHERE `TABLE_SCHEMA` = DATABASE() AND `TABLE_NAME` = 'botinventory' AND `COLUMN_NAME` = 'augslot6') > 0) THEN
UPDATE `bot_inventories` bi
INNER JOIN `botinventory` bio
ON bi.`inventories_index` = bio.`BotInventoryID`
SET bi.`augment_6` = bio.`augslot6`
WHERE bi.`bot_id` = bio.`BotID`;
END IF;
RENAME TABLE `botinventory` TO `botinventory_old`;
END IF;
I have run this script myself dozens of times on both 'clean' and convertible (existing and populated botinventory table) databases with no problems.
The script executes properly on both MySQL v5.1.73 and MariaDB v10.0.22 (both win x86)
However, I've had two reported cases of failure surrounding the 'inner' if statement.
That check is in place to catch any 'customization' that may have been done by an admin and import their data.
The failed cases are reporting: "ERROR 1136 (21S01): Column count doesn't match value count at row 1"
I walked one of the admins through the manual installation of this update and found the problem to be with the 'if' query.
EDIT: It's acting like the query inside of the con check is firing off - defeating the purpose of the check itself (NULL is greater than '0'?)
(The walk-through admin is running MySQL v5.1.x as x86 on windows server 2012..the other is running MySQL v5.1.x as win (7?) x86.)
It seems to report that error when 'augslot6' does not exist - opposite behavior of what the check is in place to prevent.
I'm just not sure whether this is a syntax/methodology issue or an actual database code bug.
Searching for similar cases almost exclusively turns up results for column-entry count mis-matches, not why an if statement proves true with a false/null result...
Any suggestions?
EDIT: I am aware of what ANSI SQL code '21S01' indicates and how it could be interpreted to mean the missing augslot6 column. But, if so, why is the 'if' query proving 'true' when it should be 'false' on some systems?
EDIT: I wasn't able to perform the failing test myself as I don't have access to these systems.

Allow Null values for indexed column or NOT NULL for indexed column in MYSQL? What is good?

I am using MYSQL as database. Check is this table definition
CREATE TABLE `test`.`header`
(
`header_id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`title` VARCHAR(500) NOT NULL,
`body` VARCHAR(5000) NOT NULL,
`created_by_id_ref` BIGINT UNSIGNED NOT NULL,
`created_date` DATETIME NOT NULL,
`updated_date` DATETIME NULL DEFAULT NULL,
`is_void` TINYINT(1) NULL DEFAULT NULL,
PRIMARY KEY (header_id`) ) ENGINE=INNODB CHARSET=latin1 COLLATE=latin1_swedish_ci;
In my interface user can delete any of the record by simply selecting the record from a grid view. So in that case I am simply updating the "is_void" status to true.
I declared that column by this syntax. which shows above. Here it again.
`is_void` TINYINT(1) NULL DEFAULT NULL,
So If I add an index to this column is this column declaration is good?
In that case records default have null values. For voided records it will be "1".
So if I am going to filter any of those records for voided records I have to use
Select ........ where is_void=1;
If I want to filter non voided records I can use
Select ........ where is_void IS NULL;
So is this NULL declaration affect to my select query performance? (Remember I indexed this column)
Or Shall I declare my column as
`is_void` TINYINT(1) NOT NULL,
and then I have insert "0" for non voided records. Then if I want to filter non voided records I can use
Select ........ where is_void=0;
So What is the best?
where is_void=0; or where is_void IS NULL;
Thank you very much.
In terms of performances, both approaches are equivalent*.
In terms of logic, NULL is widely regarded as meaning "unknown value" or "not applicable". Go with 1 or 0, as defined by the TRUE and FALSE constants.
Also, even though MySQL implements it as an alias for TINYINT(1), I would advise using the ANSI-standard BOOLEAN type.
* Ok, this is not entirely true in theory.

timestamp to use specific timezone?

The below is my table definition that automatically inserts timestamp value into each record. All i want to do is let the timestamp use a specific timezone for example in my case i want it to use the current time of British Columbia How do i do that ?
Because when i insert data in the table i do not really pass a timestame value from my php script but it takes the default value.
CREATE TABLE `cfv_postbusupdate` (
`BusNumber` int(11) NOT NULL,
`Direction` varchar(100) DEFAULT 'Not Provided',
`StopNames` varchar(300) DEFAULT 'Not Provided',
`Status` varchar(45) DEFAULT 'Not Provided',
`comments` varchar(150) DEFAULT 'None',
`username` varchar(45) DEFAULT 'anonymous_user',
`dayofweek` varchar(45) DEFAULT NULL,
`time` varchar(20) DEFAULT NULL,
`id` int(11) NOT NULL AUTO_INCREMENT,
`DatePosted` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
Timestamps are stored as UTC values ad converted on retrieval to the time zone in use by the application. If you want British Columbia time set the time zone with SET time_zone = 'america/vancouver';
The manual reference is here
use this one: refer this link:https://stackoverflow.com/a/6158432/3242978
-- Make sure we're all working off of the same local time zone
test=> SET timezone = 'America/Los_Angeles';
SET
test=> SELECT NOW();
now
-------------------------------
2011-05-27 15:47:58.138995-07
(1 row)
test=> SELECT NOW() AT TIME ZONE 'UTC';
timezone
----------------------------
2011-05-27 22:48:02.235541
(1 row)
update: 1
According to MySQL docs, the error #1193 occurs when you use wrong code for SQLSTATE.
Message: Unknown system variable %s
And, as you can see on the same page, the SQLSTATE 99003 is not defined.