Test table used for procedure:
CREATE TABLE cities (
id int(10) unsigned NOT NULL auto_increment,
name varchar(100) NOT NULL,
PRIMARY KEY (`id`)
);
insert into cities (name) values
('London'), ('Manchester'), ('Bristol'),
('Birmingham'), ('Brighton');
Original stored procedure:
DROP PROCEDURE IF EXISTS `cities_select_by_ids` $$
CREATE PROCEDURE `cities_select_by_ids`(
in _cityIds varchar(1000)
)
BEGIN
SET @cityIds = _cityIds;
PREPARE stmt FROM '
select
id,
name
from cities
where id in (?);
';
EXECUTE stmt USING @cityIds;
DEALLOCATE PREPARE stmt;
END $$
DELIMITER ;
call cities_select_by_ids_prepare('1, 2, 3');
#-- Only 1 city name returned (London).
One work around would be to split the string into individual elements and run the select as below.
DROP PROCEDURE IF EXISTS `cities_select_by_ids_2` ;
CREATE PROCEDURE `cities_select_by_ids_2`(
in cityIDs varchar(1000)
)
BEGIN
#- ix - index into the list of city IDs
#- cid - city ID
SET @ix := 1;
SET @cid := substring_index(cityIDs, ',', @ix);
LOOP_1:
WHILE (@cid is not null) DO
SELECT id, name
FROM cities
WHERE id in (@cid) ;
#-- substring_index returns complete cityIDs string when index is > number of elements
IF (length(substring_index(cityIDs, ',', @ix)) >= length(cityIDs)) THEN
LEAVE LOOP_1;
END IF;
SET @ix := @ix + 1;
SET @cid = substring_index(substring_index(cityIDs, ',', @ix), ',', -1);
END WHILE;
END
#----
call cities_select_by_ids_2('1, 2, 3');
The problem is that you queried 3 times, in a stored procedure. Which is slower that concatinated SELECT query.
ReplyDeleteIt is returning the required results but is not optimized for performance as you correctly noted.
Delete/* Only Works in MySQL 5.0 and above */
ReplyDeleteBEGIN
SET @sql_text:=concat(
'SELECT
id,
name
FROM db.table
WHERE
ProjectId IN
(',
/* BEGIN Parameter */
'1,2,3',
/* END Parameter */
' ORDER BY id ASC');
PREPARE stmt from @sql_text;
EXECUTE stmt ;
DEALLOCATE PREPARE stmt;
END
Thanks for the above code snippet.
ReplyDelete