Reputation: 279
The query below performs poorly on a production database but seems fine on a development database. All the tables involved are identical, same columns, datatype, indexes, etc. The production database has slightly more records (maybe +10%). In SSMS the query takes 25-30 seconds to return any results, <1 sec on the dev copy.
The query is generated by a web based crm application via php code. (SuiteCrm) The production and dev database are on the same server. The dev copy was created by restoring a backup of the production db. I do see differences between the two execution plans but I don't understand why they would differ if the tables are identical. (I don't have any experience with execution plans)
SELECT TOP (@topcount) *
FROM (SELECT contacts.id,
LTRIM(RTRIM(ISNULL(contacts.first_name, '') + N' '
+ ISNULL(contacts.last_name, ''))) AS NAME,
contacts.first_name,
contacts.last_name,
contacts.salutation,
accounts.NAME account_name,
jtl0.account_id account_id,
contacts.title,
contacts.phone_work,
jt1.user_name assigned_user_name,
jt1.created_by assigned_user_name_owner,
N'Users' assigned_user_name_mod,
contacts.date_entered,
contacts.date_modified,
contacts.assigned_user_id,
ROW_NUMBER()
OVER (
ORDER BY contacts.date_modified ASC) AS row_number
FROM contacts
LEFT JOIN contacts_cstm
ON contacts.id = contacts_cstm.id_c
LEFT JOIN accounts_contacts jtl0
ON contacts.id = jtl0.contact_id
AND jtl0.deleted = 0
LEFT JOIN accounts accounts
ON accounts.id = jtl0.account_id
AND accounts.deleted = 0
AND accounts.deleted = 0
LEFT JOIN users jt1
ON contacts.assigned_user_id = jt1.id
AND jt1.deleted = 0
AND jt1.deleted = 0
WHERE (( ( LTRIM(RTRIM(ISNULL(contacts.first_name, ''))) LIKE N'abe krebs%'
OR LTRIM(RTRIM(ISNULL(contacts.first_name, ''))) LIKE N'abe krebs%' )
OR ( LTRIM(RTRIM(ISNULL(contacts.last_name, ''))) LIKE N'abe krebs%'
OR LTRIM(RTRIM(ISNULL(contacts.last_name, ''))) LIKE N'abe krebs%' )
OR (( contacts.phone_mobile LIKE N'abe krebs%'
OR contacts.phone_work LIKE N'abe krebs%'
OR contacts.phone_other LIKE N'abe krebs%'
OR contacts.phone_fax LIKE N'abe krebs%'
OR LTRIM(RTRIM(ISNULL(contacts.phone_mobile, '') + N' '
+ ISNULL(contacts.phone_work, '') + N' '
+ ISNULL(contacts.phone_other, '') + N' '
+ ISNULL(contacts.phone_fax, '') + N' '
+ ISNULL(contacts.assistant_phone, ''))) LIKE N'abe krebs%'
OR LTRIM(RTRIM(ISNULL(contacts.assistant_phone, '') + N' '
+ ISNULL(contacts.phone_fax, '') + N' '
+ ISNULL(contacts.phone_other, '') + N' '
+ ISNULL(contacts.phone_work, '') + N' '
+ ISNULL(contacts.phone_mobile, ''))) LIKE N'abe krebs%' ))
OR ( LTRIM(RTRIM(ISNULL(contacts.assistant, ''))) LIKE N'abe krebs%'
OR LTRIM(RTRIM(ISNULL(contacts.assistant, ''))) LIKE N'abe krebs%' )
OR ( contacts.id IN (SELECT bean_id
FROM (SELECT eabr.bean_id
FROM email_addr_bean_rel eabr
JOIN email_addresses ea
ON ( ea.id = eabr.email_address_id )
WHERE eabr.deleted = 0
AND ea.email_address LIKE N'abe krebs%') email_derived) )
OR ( LTRIM(RTRIM(ISNULL(accounts.NAME, ''))) LIKE N'abe krebs%'
OR LTRIM(RTRIM(ISNULL(accounts.NAME, ''))) LIKE N'abe krebs%' )
OR (( contacts.first_name LIKE N'abe krebs%'
OR LTRIM(RTRIM(ISNULL(contacts.first_name, '') + N' '
+ ISNULL(contacts.last_name, ''))) LIKE N'abe krebs%'
OR LTRIM(RTRIM(ISNULL(contacts.last_name, '') + N' '
+ ISNULL(contacts.first_name, ''))) LIKE N'abe krebs%' )) ))
AND contacts.deleted = 0) AS a
WHERE row_number > 0
I've noticed that the query performance is fine if I remove
SELECT TOP (@topcount) * FROM
or remove
( contacts.id IN
(select bean_id
from (SELECT eabr.bean_id ...
or remove
OR ( LTRIM(RTRIM(ISNULL(accounts.name,''))) LIKE N'abe krebs%'
OR LTRIM(RTRIM(ISNULL(accounts.name,''))) LIKE N'abe krebs%' )
Something else that concerns me is if I try to run the database tuning advisor on the production db the DTA crashes every time, even if I select one small table. There is a maintenance plan with Reorganize Index that runs nightly. I checked everything I can think of and can't find any differences between the two databases. What could be causing the poor performance and why only on the one database?
Upvotes: 0
Views: 110
Reputation: 96600
First that code is horrendous. This is a prime example of why you should not generate sql code. If you really need all those LTRIM, RTRIM functions for instance, then your database design needs work too. And you have the same OR condition in there multiple times.
(((LTRIM(RTRIM(ISNULL(contacts.first_name,''))) LIKE N'abe krebs%'
OR LTRIM(RTRIM(ISNULL(contacts.first_name,''))) LIKE N'abe krebs%' )
OR ( LTRIM(RTRIM(ISNULL(contacts.last_name,''))) LIKE N'abe krebs%'
OR LTRIM(RTRIM(ISNULL(contacts.last_name,''))) LIKE N'abe krebs%' )
Plus what is going on with your database design if this is even something you want to check:
OR ( ( contacts.phone_mobile like N'abe krebs%'
OR contacts.phone_work like N'abe krebs%'
OR contacts.phone_other like N'abe krebs%'
OR contacts.phone_fax like N'abe krebs%'
Or
OR ( contacts.id IN
(select bean_id
from (SELECT eabr.bean_id
FROM email_addr_bean_rel eabr JOIN email_addresses ea ON (ea.id = eabr.email_address_id)
WHERE eabr.deleted=0 AND ea.email_address LIKE N'abe krebs%') email_derived))
After all very few email addresses have spaces in them.
OR conditions generally slow down performance and by adding a bunch of them that will never affect the result you are creating performance problems.
if you are passing in the full name of this person why are you using like?
If you have both a first and last name field what is the liklihood that this name even exists properly inthat field? I can't even be sure you are getting the correct results, but I woudl find it highly unlikely.
LTRIM(RTRIM(ISNULL(contacts.first_name,''))) LIKE N'abe krebs%' )
OR ( LTRIM(RTRIM(ISNULL(contacts.last_name,''))) LIKE N'abe krebs%'
this makes more sense to me
where contacts.first_name = N'abe'
and contacts.last_name= N'krebs'
On the other hand if you are stuck with this code for reasons beyond your control, I would suspect that the difference between prod and dev comes down to two things. First statistics may be out of date (this is different from indexing).
Second, some people develop on dev databases that are considerably smaller than the prod ones. That is always a bad idea. Code that runs fine on a small dataset is often poorly performing on a large one.
Upvotes: 1