MySQL SELECT query with joins takes too long - mysql

I have the following SELECT query with table joins and it taking about a minute to return 6 records:
SELECT * FROM specimen, topography_index, morphology, specimen_image_lookup, image
WHERE
SUBSTRING(specimen.topography_index, 2, 2) = topography_index.topography_index_code
AND
morphology.morphology_code = specimen.snop_code
AND
specimen_image_lookup.specimen_fk = specimen.specimen_pk
AND
image.image_pk = specimen_image_lookup.image_fk
AND
specimen.topography_index, 2, 2) IN('".implode("','",$system)."')
Any ideas what I should here?
Table structures are:
CREATE TABLE `specimen` (
`specimen_pk` int(4) NOT NULL AUTO_INCREMENT,
`number` varchar(20) NOT NULL,
`unit_number` varchar(10) NOT NULL,
`topography_index` varchar(5) NOT NULL DEFAULT '',
`snop_axis` char(1) NOT NULL,
`snop_code` varchar(4) NOT NULL,
`example` int(2) NOT NULL,
`gender` char(1) NOT NULL,
`age` varchar(3) NOT NULL DEFAULT 'NA',
`clinical_history` text NOT NULL,
`specimen` text NOT NULL,
`macroscopic` text NOT NULL,
`microscopic` text NOT NULL,
`conclusion` text NOT NULL,
`comment` text NOT NULL,
`room` char(1) NOT NULL,
`position` varchar(8) NOT NULL,
`created` datetime NOT NULL,
`created_by` int(3) NOT NULL,
`updated` datetime NOT NULL,
`updated_by` int(3) NOT NULL,
PRIMARY KEY (`specimen_pk`),
FULLTEXT KEY `clinical_history` (`clinical_history`),
FULLTEXT KEY `specimen` (`specimen`),
FULLTEXT KEY `macroscopic` (`macroscopic`),
FULLTEXT KEY `microscopic` (`microscopic`),
FULLTEXT KEY `conclusion` (`conclusion`),
FULLTEXT KEY `comment` (`comment`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=500 ;
CREATE TABLE `topography_index` (
`topography_index_pk` int(3) NOT NULL AUTO_INCREMENT,
`topography_index_code` varchar(2) DEFAULT NULL,
`topography_index_nomen` text,
PRIMARY KEY (`topography_index_pk`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=138 ;
CREATE TABLE `specimen_image_lookup` (
`specimen_image_lookup_pk` int(8) NOT NULL AUTO_INCREMENT,
`specimen_fk` int(4) NOT NULL,
`image_fk` int(4) NOT NULL,
PRIMARY KEY (`specimen_image_lookup_pk`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=141 ;
CREATE TABLE `morphology` (
`morphology_pk` int(6) NOT NULL AUTO_INCREMENT,
`morphology_code` varchar(4) NOT NULL,
`morphology_nomen` varchar(120) NOT NULL,
PRIMARY KEY (`morphology_pk`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=2295 ;
CREATE TABLE `image` (
`image_pk` int(4) NOT NULL AUTO_INCREMENT,
`image_title` varchar(80) NOT NULL,
`image_description` text NOT NULL,
`image_thumbnail` varchar(100) NOT NULL,
`image_small` varchar(100) NOT NULL,
`image_large` varchar(100) NOT NULL,
`created` datetime NOT NULL,
`created_by` int(3) NOT NULL,
`updated` datetime NOT NULL,
`updated_by` int(3) NOT NULL,
PRIMARY KEY (`image_pk`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=138 ;

By performing a substring on specimen.topography_index, you're asking the database to perform that calculation on every row in the specimen table before finding if the value exists in topography_index. One way to address this is to store the actual integer value that will match with topography_index, rather than a string with that value embedded.

Related

select from two tables each with different join

Trying to run this query will not return any error but I guess there is still something wrong in it. After four minutes running it keeps elaborating:
SELECT DISTINCT azioni_row.id_az, sofferenze.Descrizione, COUNT(crediti.stato = 'aperta') as aperti, COUNT(crediti.stato = 'chiusa') as chiusi
FROM (`azioni_row`, sofferenze)
JOIN crediti ON azioni_row.id_cred=crediti.id_cre
JOIN azioni_head as ah1 ON azioni_row.id_az=ah1.id_az
JOIN azioni_head as ah2 ON ah2.id_soff = sofferenze.id_soff
GROUP BY id_az
ORDER BY `azioni_row`.`id_az` ASC
If I remove sofferenze.Descrizione from the select list and sofferenze from the FROM list it runs in a few seconds:
SELECT DISTINCT azioni_row.id_az, COUNT(crediti.stato = 'aperta') as aperti, COUNT(crediti.stato = 'chiusa') as chiusi
FROM azioni_row
JOIN crediti ON azioni_row.id_cred=crediti.id_cre
JOIN azioni_head as ah1 ON azioni_row.id_az=ah1.id_az
GROUP BY id_az
ORDER BY `azioni_row`.`id_az` ASC
I would like to show the Descrizione field but the link for it is in the head table, not in the row one. The relationship between head and row is a one to many. I store in head all the info that is not necessary to repeat for each row and the link with Descrizione is one of these fields.
EDIT:
this is the explain:
this is the create for azioni_head:
CREATE TABLE `azioni_head` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`tipo` varchar(2) NOT NULL,
`id_az` varchar(11) NOT NULL,
`id_soff` varchar(11) NOT NULL,
`id_soff_gar` varchar(11) DEFAULT NULL,
`date_from` date NOT NULL,
`date_to` date NOT NULL,
`close_why` int(11) NOT NULL,
`RGE` varchar(30) NOT NULL,
`procedente` varchar(2) NOT NULL,
`curatore` varchar(11) NOT NULL,
`legale` varchar(11) NOT NULL,
`tribunale` varchar(11) NOT NULL,
`riparto` varchar(2) NOT NULL DEFAULT '0',
`perc_worst` decimal(13,10) NOT NULL,
`perc_best` decimal(13,10) NOT NULL,
`perc_poster` decimal(13,10) NOT NULL,
`attivo_storico` decimal(65,2) NOT NULL,
`passivo_storico` decimal(65,2) NOT NULL,
`attivo_storico_comm` decimal(65,2) NOT NULL,
`passivo_storico_comm` decimal(65,2) NOT NULL,
`acconti` decimal(65,2) NOT NULL,
`acconti_comm` decimal(65,2) NOT NULL,
`numero_comm` int(11) NOT NULL,
`legali_worst` decimal(65,2) NOT NULL,
`legali_best` decimal(65,2) NOT NULL,
`manuale` tinyint(1) NOT NULL DEFAULT '0',
`created_by` int(11) NOT NULL,
`created_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1449 DEFAULT CHARSET=utf8 COMMENT='tabella testata azioni'
this for azioni_row:
CREATE TABLE `azioni_row` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_az` varchar(11) NOT NULL,
`id_cred` varchar(11) NOT NULL,
`chiesto` decimal(65,2) NOT NULL,
`ammesso` decimal(65,2) NOT NULL,
`data_ammesso` date NOT NULL,
`rango_ammesso` tinytext NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4479 DEFAULT CHARSET=utf8
and this for sofferenze
CREATE TABLE `sofferenze` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_soff` varchar(11) NOT NULL,
`Descrizione` tinytext NOT NULL,
`gruppo` int(11) NOT NULL,
`cointestazione` int(11) NOT NULL,
`port_man` tinytext NOT NULL,
`head_port_man` tinytext NOT NULL,
`note` longtext NOT NULL,
`created_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`created_by` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`),
UNIQUE KEY `id_3` (`id`),
KEY `id_2` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1716 DEFAULT CHARSET=utf8
Please provide proper CREATE statements as well as the output of:
EXPLAIN
SELECT a.id_az
, s.Descrizione
, COUNT(c.stato = 'aperta') aperti
, COUNT(c.stato = 'chiusa') chiusi
FROM azioni_row a
JOIN sofferenze s
CROSS
JOIN crediti c
ON c.id_cre = a.id_cred
JOIN azioni_head ah1
ON ah1.id_az = a.id_az
JOIN azioni_head ah2
ON ah2.id_soff = s.id_soff
GROUP
BY a.id_az
, s.Descrizione
ORDER
BY a.id_az ASC
Edit: You seem to have lots of indexes on the same column. Drop all indexes except the PRIMARY KEYs, and create the following indexes:
sofferenze: id_soff
azioni_row: try a composite index on (id_az,id_cred)
azioni_head: an index on id_soff and an index on id_az
Crediti is missing so I can't comment on that one.

Mysql error 1215 - Cannot add foreign key constraint

Created these two tables successfully
First table
CREATE TABLE IF NOT EXISTS `lawncare_user` (
`ID` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`FirstName` varchar(255) NOT NULL,
`LastName` varchar(255) NOT NULL,
`Email` varchar(255) NOT NULL,
`UserType` varchar(30) NOT NULL,
`UserName` varchar(255) NOT NULL,
`Password` varchar(255) NOT NULL,
`AddedBy` int(11) NOT NULL,
`AddedOn` date NOT NULL,
`ModifiedOn` date DEFAULT NULL,
`Status` BOOLEAN NOT NULL DEFAULT '0',
`QuestionID` int(11) DEFAULT NULL,
`QuestionAnswer` text DEFAULT NULL,
`Params` text NOT NULL,
`Address` text NOT NULL,
`Country` varchar(300) NOT NULL,
`State` varchar(300) NOT NULL,
`City` varchar(300) NOT NULL,
`ContactNo` double DEFAULT NULL,
`Activation` BOOLEAN NOT NULL DEFAULT '0',
`ActivatedOn` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Second table
CREATE TABLE IF NOT EXISTS `lawncare_customer` (
`ID` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`FirstName` varchar(255) NOT NULL,
`LastName` varchar(255) NOT NULL,
`Email` varchar(255) NOT NULL,
`Password` varchar(255) NOT NULL,
`ContactNo` varchar(20) NOT NULL,
`Address` varchar(255) NOT NULL,
`Params` text NOT NULL,
`Province` varchar(255) NOT NULL,
`ZipCode` varchar(255) NOT NULL,
`Status` Boolean NOT NULL DEFAULT '0',
`AddedBy` int(11) NOT NULL,
`AddedOn` date NOT NULL,
`ModifiedOn` date DEFAULT NULL
) ENGINE =InnoDB DEFAULT CHARSET=latin1;
But while creating third table as
CREATE TABLE IF NOT EXISTS `lawncare_message` (
`ID` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`Reason` int(5) NOT NULL,
`Subject` text NOT NULL,
`Description` text NOT NULL,
`Customer` int(11) NOT NULL,
`CustomerUser` varchar(255) NOT NULL,
`CustomerEmail` varchar(255) NOT NULL,
`SendTo` int(11) NOT NULL,
`SendToUser` varchar(255) NOT NULL,
`SendToEmail` varchar(255) NOT NULL,
`Status` int(5) NOT NULL DEFAULT '0',
`AddedBy` int(11) NOT NULL,
`AddedOn` date NOT NULL
FOREIGN KEY (SendTo, SendToUser, SendToEmail)
REFERENCES lawncare_user(ID, UserName, Email)
ON UPDATE CASCADE ,
FOREIGN KEY (Customer, CustomerUser, CustomerEmail)
REFERENCES lawncare_customer(ID, FirstName,Email)
ON UPDATE CASCADE
) ENGINE =InnoDB DEFAULT CHARSET=latin1
I get #1215 - Cannot add foreign key constraint , error in mysql tried adding foreign keys after creating table but it still gives the same error. I don't know what I'm doing wrong here.
First of all Check whether you have applied indexes on the keys.
As per your code their is no point in referencing id,UserName and Email.
Only id is enough for referencing.
Check the following code
CREATE TABLE IF NOT EXISTS `lawncare_message` (
`ID` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`Reason` int(5) NOT NULL,
`Subject` text NOT NULL,
`Description` text NOT NULL,
`Customer` int(11) NOT NULL,
`CustomerUser` varchar(255) NOT NULL,
`CustomerEmail` varchar(255) NOT NULL,
`SendTo` int(11) NOT NULL,
`SendToUser` varchar(255) NOT NULL,
`SendToEmail` varchar(255) NOT NULL,
`Status` int(5) NOT NULL DEFAULT '0',
`AddedBy` int(11) NOT NULL,
`AddedOn` date NOT NULL,
FOREIGN KEY (SendTo)
REFERENCES lawncare_user(ID)
ON UPDATE CASCADE ,
FOREIGN KEY (Customer)
REFERENCES lawncare_customer(ID)
ON UPDATE CASCADE
) ENGINE =InnoDB DEFAULT CHARSET=latin1

MySQL insert using transaction

I have following structure on mysql database:
sqlfiddle
What I want to do is:
To select DISTINCT industry from Company table
To insert into Industry table first and get auto incremented ID
With this ID to insert again into IndustryTranslation table and set "language"="en"
To insert Company's id and newly generated Industry's id into MapCompanyIndustry table
I know that it's not possible with one statement. But definitely it's possible with transaction. Can't figure out how to achieve this result with one transaction.
Any suggestions?
Schema
CREATE TABLE `Industry` (
`id` int(4) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `IndustryTranslation` (
`industryID` int(4) unsigned NOT NULL,
`language` varchar(5) NOT NULL,
`name` varchar(255) NOT NULL,
`confirmed` tinyint(1) DEFAULT '0',
PRIMARY KEY (`industryID`,`language`),
KEY `language` (`language`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `Company` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`imageUri` varchar(255) DEFAULT NULL,
`countryID` int(3) unsigned DEFAULT NULL,
`phone` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`verified` tinyint(1) DEFAULT NULL,
`industry` varchar(255) DEFAULT NULL,
`headquarters` varchar(255) DEFAULT NULL,
`uri` varchar(255) DEFAULT NULL,
`createdAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`updatedAt` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `countryID` (`countryID`)
) ENGINE=InnoDB AUTO_INCREMENT=4004 DEFAULT CHARSET=utf8;
CREATE TABLE `MapCompanyIndustry` (
`companyID` int(10) unsigned NOT NULL,
`industryID` int(4) unsigned NOT NULL,
PRIMARY KEY (`companyID`,`industryID`),
KEY `industryID` (`industryID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

#1415 - Not allowed to return a result set from a trigger

DELIMITER $$
CREATE TRIGGER `msg_after_insert`
AFTER INSERT ON `meter_reading`
FOR EACH ROW
BEGIN
select meter_reading.*,a.amount as Light_Reading_Amt,b.amount as Power_Reading_Amt from meter_reading inner join master_unit a on a.min_unit<=msg1 and msg1<=a.max_unit and doc>=a.date_of_enter_value_fm inner join master_unit b on b.min_unit<=msg2 and msg2<=b.max_unit and doc<=b.date_of_enter_value_to;
INSERT INTO `smsd`.`outbox` (DestinationNumber,TextDecoded) VALUES (NEW.mobno, CONCAT_WS(NEW.msg1,NEW.Light_Reading_Amt,' ',NEW.msg2,NEW.Light_Reading_Amt));
END $$
DELIMITER ;
My databases are
1. mr_sms (tables are : 1.meter_reading 2.master_unit)
--meter_reading table--
CREATE TABLE IF NOT EXISTS `meter_reading` (
`serno` int(50) NOT NULL AUTO_INCREMENT,
`cno` varchar(50) DEFAULT NULL,
`accn_no` varchar(20) DEFAULT NULL,
`loc` varchar(20) DEFAULT NULL,
`type_of_accn` varchar(50) NOT NULL,
`rank` varchar(25) NOT NULL,
`name` varchar(50) DEFAULT NULL,
`mobno` varchar(15) DEFAULT NULL,
`msg1` int(100) DEFAULT NULL,
`msg2` int(250) NOT NULL,
`status` varchar(30) NOT NULL,
`doc` date NOT NULL,
`remarks` varchar(100) DEFAULT NULL,
PRIMARY KEY (`serno`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=22 ;
--master_unit table--
CREATE TABLE IF NOT EXISTS `master_unit` (
`u_id` int(11) NOT NULL AUTO_INCREMENT,
`min_unit` int(150) NOT NULL,
`max_unit` int(200) NOT NULL,
`rate` varchar(20) NOT NULL,
`amount` varchar(20) NOT NULL,
`duty` varchar(20) NOT NULL,
`dutyamount` varchar(20) NOT NULL,
`date_of_enter_value_fm` date NOT NULL,
`date_of_enter_value_to` date NOT NULL,
PRIMARY KEY (`u_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=10 ;
2. smsd (table is : outbox)
--
-- Table structure for table `outbox`
--
CREATE TABLE IF NOT EXISTS `outbox` (
`UpdatedInDB` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`InsertIntoDB` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`SendingDateTime` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`SendBefore` time NOT NULL DEFAULT '23:59:59',
`SendAfter` time NOT NULL DEFAULT '00:00:00',
`Text` text,
`DestinationNumber` varchar(20) NOT NULL DEFAULT '',
`Coding` enum('Default_No_Compression','Unicode_No_Compression','8bit','Default_Compression','Unicode_Compression') NOT NULL DEFAULT 'Default_No_Compression',
`UDH` text,
`Class` int(11) DEFAULT '-1',
`TextDecoded` text NOT NULL,
`ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`MultiPart` enum('false','true') DEFAULT 'false',
`RelativeValidity` int(11) DEFAULT '-1',
`SenderID` varchar(255) DEFAULT NULL,
`SendingTimeOut` timestamp NULL DEFAULT '0000-00-00 00:00:00',
`DeliveryReport` enum('default','yes','no') DEFAULT 'default',
`CreatorID` text NOT NULL,
PRIMARY KEY (`ID`),
KEY `outbox_date` (`SendingDateTime`,`SendingTimeOut`),
KEY `outbox_sender` (`SenderID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ;
--
-- Dumping data for table `outbox`
--

How to optimize a MySQL JOIN Query

I have this MySQL query that I want to optimize:
SELECT r.WarehouseLocation,sum(sir.qty)
FROM repairableissue as r
INNER JOIN SIR ON r.sirno=sir.sirno
AND r.region=sir.region
AND r.ItemName=sir.Itemdesc
AND r.SerialNo=sir.Serialno
WHERE r.status='Pending'
GROUP BY r.warehouseLocation
How do I optimize this query? I read about optimization and found out that indexes might help but still could not achieve the desired performance.
Which index should be used and which should be removed?
Below is the explain of query:
Repairableissue
CREATE TABLE `repairableissue` (
`Vendor` varchar(40) NOT NULL,
`ItemName` varchar(200) NOT NULL,
`SerialNo` varchar(50) NOT NULL,
`person` varchar(200) NOT NULL,
`siteid` varchar(10) NOT NULL,
`invuser` varchar(50) NOT NULL,
`region` varchar(50) NOT NULL,
`id` int(11) NOT NULL AUTO_INCREMENT,
`Dated` date NOT NULL,
`Sirno` varchar(50) NOT NULL,
`status` varchar(30) NOT NULL DEFAULT 'Pending',
`trackthrough` varchar(30) NOT NULL,
`reason` varchar(100) NOT NULL,
`ckh` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`WarehouseType` varchar(20) NOT NULL,
`WarehouseLocation` varchar(20) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`),
KEY `I1` (`status`),
KEY `ind2` (`ItemName`),
KEY `ind3` (`region`),
KEY `ind5` (`SerialNo`),
KEY `ind4` (`Sirno`)
) ENGINE=MyISAM AUTO_INCREMENT=63029 DEFAULT CHARSET=latin1
sir
CREATE TABLE `sir` (
`SirNo` varchar(50) NOT NULL,
`SiteId` varchar(80) NOT NULL,
`Vendor` varchar(70) NOT NULL,
`Type` varchar(15) NOT NULL,
`ItemDesc` varchar(200) NOT NULL,
`ItemCode` varchar(25) NOT NULL,
`SerialNo` varchar(50) NOT NULL,
`Unit` varchar(15) NOT NULL,
`AssetCode` varchar(50) NOT NULL,
`Qty` decimal(11,0) NOT NULL,
`Region` varchar(15) NOT NULL,
`Status` varchar(20) NOT NULL DEFAULT 'Installed',
`FaultInfo` varchar(100) NOT NULL DEFAULT 'date()',
`chk` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`Phase` varchar(15) NOT NULL,
`Category` varchar(200) NOT NULL,
`Issue_Vendor` varchar(30) NOT NULL,
`AssetName` varchar(150) NOT NULL,
`Ownership` varchar(20) NOT NULL,
`Dated` date NOT NULL,
`PersonName` varchar(150) NOT NULL,
`Remarks` varchar(300) NOT NULL,
`po` varchar(100) NOT NULL,
`invuser` varchar(50) NOT NULL,
`id` int(11) NOT NULL AUTO_INCREMENT,
`grnno` varchar(30) NOT NULL,
`WarehouseType` varchar(20) NOT NULL,
`WarehouseLocation` varchar(20) NOT NULL,
`mainpartserial` varchar(200) NOT NULL,
PRIMARY KEY (`Vendor`,`Type`,`ItemCode`,`ItemDesc`,`SerialNo`,`Ownership`,`SirNo`,`Region`,`WarehouseType`,`WarehouseLocation`,`po`,`Qty`,`id`),
KEY `id` (`id`),
KEY `ind4` (`ItemDesc`),
KEY `ind6` (`SerialNo`),
KEY `ind7` (`SerialNo`)
) ENGINE=MyISAM AUTO_INCREMENT=228007 DEFAULT CHARSET=latin1
One multi-column index on r.status + r.warehouseLocation, in that order.
One multi-column index on sir.sirno + sir.region + sir.Itemdesc + sir.Serialno, in order of most cardinality to least cardinality, with sir.qty tacked on the end.
This assumes the fields are small enough to fit (combined) into an index.
Still, join seeks are unavoidable. The number of records that match r.status='Pending' is going to dictate the speed of this query.