Reputation: 39
I have a query in Sql Server that I will like to optimize.
SELECT user_type_name = CASE user_type_id
WHEN 1 THEN 'Admin'
WHEN 5 THEN 'Super Admin'
WHEN 3 THEN 'Writer'
WHEN 4 THEN 'Reader'
END,
user_can_log = CASE user_inactive
WHEN 1 THEN 'No'
ELSE 'Yes'
END,
(SELECT COUNT(*)
FROM t_fthread
WHERE fthread_creator_userid = user_id) AS number_tickets,
(SELECT COUNT(*)
FROM t_email
WHERE email_to LIKE '%' + user_email + '%'
OR email_cc LIKE '%' + user_email + '%') AS number_emails,
*
FROM t_user
LEFT JOIN t_organisation
ON user_org_id = organisation_id
WHERE user_org_id = 42
ORDER BY user_last_name,
user_first_name
The query takes too much time to run. thanks to query analyzer, I've identified the part in the query that takes too much time, It's this section:
(select count(*) from t_email where email_to like '%'+user_email+'%' or email_cc like '%'+user_email+'%') as number_emails.
I'm trying to rewrite the query to still get the number_emails but in every case, it's still very slow.
I've tried to create the indexes, but it's impossible to create index on user_email and user_cc. Both columns are ntext types and on sql server 2000, it's not possible to create index on theses columns. I've run analyze the query with Database Engine Tune Advisor and I've run the recommendations provided by the tools.
CREATE NONCLUSTERED INDEX [_dta_index_t_fthread_15_2073058421__K5] ON [dbo].[t_fthread]
(
[fthread_creator_userid] ASC
)
CREATE STATISTICS [_dta_stat_1365579903_4_3] ON [dbo].[t_user]([user_last_name], [user_first_name])
CREATE STATISTICS [_dta_stat_1365579903_1_5] ON [dbo].[t_user]([user_id], [user_org_id])
CREATE NONCLUSTERED INDEX [_dta_index_t_user_15_1365579903__K5_K1] ON [dbo].[t_user]
(
[user_org_id] ASC,
[user_id] ASC
)
But the query still takes lot of time to finish the execution.
Upvotes: 0
Views: 275
Reputation: 2655
Your query indicates bad design. You should either
Requirement: all users from to and cc are in your database (no emails sent to email addresses out of organization)
Instead of storing emails in to
and cc
, create new tables and store email id as well as user_ids from to and cc.
Add two columns (Number_To, Number_CC
) in t_user
table and increment them as needed (when sending emails, storing it to t_email
table, ...). If You decide to go this way, watch out for concurrency, it is best to do UPDATE t_user SET Number_To = Number_To + 1
instead of selecting current Number_To
value and then updating to new value.
Upvotes: 3
Reputation: 77876
Try this query once. Also, try =
operator instead LIKE
SELECT tu.*,
(case when user_type_id = 1 then 'Admin'
when user_type_id = 5 then 'Super Admin'
when user_type_id = 3 then 'Writer'
when user_type_id = 4 then 'Reader'
else 'somethingelse'
end) as user_type_name,
(case when user_inactive = 1 then 'No'
else 'Yes' end) as user_can_log,
(select count(*) as number_tickets from t_fthread where
fthread_creator_userid=user_id()),
(select count(*) as number_emails from t_email where email_to like '%[email protected]%'
or email_cc like '%[email protected]%')
FROM t_user tu left join t_organisation torg on tu.user_org_id=
torg.organisation_id where tu.user_org_id = 42 order by tu.user_last_name,
tu.user_first_name
Upvotes: 0
Reputation: 4949
Well, you could do the following for the email:
SELECT COUNT(*)
FROM t_email
WHERE
(
PATINDEX('%' + user_email + '%', email_to) != 0
OR PATINDEX('%' + user_email + '%', email_cc) != 0
)
Upvotes: 0
Reputation: 2605
Is it possible to do the search using:
email_to like user_email+'%'
, or even code all alternatives? Or, even better, store the user email (that will being searched for later) in a "cleansed" form in the database?
The wildcard in front of user_email is the evil one: textual searches starting with '%' will always be slow, because they're unpredictable, and you'll never know where in the string the search text will be found.
For example, consider the text:
[email protected]@this.text
While this is a relatively small string, the search for the text "[email protected]" will go like this
this goes two times on, and the third time the ''@'' is found. Then mismatch at position four.
Only after about 36 comparison-operations, SQL Server knows the string matches. And that is for one row only.. So try to avoid wildcards at the beginning of string comparisons.
Upvotes: 0