Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 SQL Server 2000 Forums
 SQL Server Development (2000)
 Query takes over 10 minutes....why?

Author  Topic 

label
Posting Yak Master

197 Posts

Posted - 2003-04-10 : 15:02:48
The following query takes over 10 minutes to process in the Query Analyzer.

quote:

CREATE PROCEDURE ap_get_activity_by_country

@fromdate datetime

AS

Begin

set nocount on

Create table #temp (country varchar(50), country_count int, country_count_recent int, percent_active float, percent_active_recent float, download_count int, avg_download int)

Declare Cursid Cursor for
select distinct(country) from smc_new_products.dbo.usr_smc
where country<>''

Open cursid

Declare @country varchar(50),
@country_count int,
@country_count_recent int,
@active_users int,
@percent_active float,
@percent_active_recent float,
@download_count int,
@avg_download int

Fetch next from Cursid into @country
while (@@fetch_status<>-1)
Begin

--Grab how many users are registered in each country
select @country_count=count([user_id]) from smc_new_products.dbo.usr_smc where country=@country

--Grab how many users are registered in each country
select @country_count_recent=count([user_id]) from smc_new_products.dbo.usr_smc where country=@country
and
[user_id] in
(select [user_id] from smc_new_products.dbo.usr where user_create_time between @fromdate and getdate())

--Grab how many users are active within the timeperiod provided
select @active_users=count(distinct(username)) from smc_new_products.dbo.etechmodelrequests
where requestdatetime between @fromdate and getdate()
and interfacename like '%download%'
and username in
(select convert(varchar(50), [user_id]) from smc_new_products.dbo.usr_smc where country=@country)

--Calculate Active users versus all registered users
if @active_users>0
Begin
Select @percent_active=(@active_users/@country_count)
end
else
Begin
select @percent_active=0
end

--Calculate Active users versus only users registered in specified time frame
if @active_users>0
Begin
Select @percent_active_recent=(@active_users/@country_count_recent)
end
else
Begin
select @percent_active=0
end

--Grab how many downloads
select @download_count=count(username) from smc_new_products.dbo.etechmodelrequests
where requestdatetime between @fromdate and getdate()
and interfacename like '%download%'
and username in
(select convert(varchar(50), [user_id]) from smc_new_products.dbo.usr_smc where country=@country)

--Calculate Average download per user
if @active_users>0 and @download_count>0
Begin
select @avg_download=(@download_count/@active_users)
end
else
Begin
select @avg_download=0
end


--Insert values
insert into #temp values (@country, @country_count, @country_count_recent, @percent_active, @percent_active_recent, @download_count, @avg_download)

Fetch next from Cursid into @country
end

--Clean up
deallocate cursid

select * from #temp order by country_count desc

end
GO




Does anyone have any suggestions on how to make it run quicker or is this about all I can do for the type of data I want to return?


jsmith8858
Dr. Cross Join

7423 Posts

Posted - 2003-04-10 : 15:26:41
Try this. read it carefully, it may not be right, I am only guessing -- it is hard to know what you are trying to do w/o your table structure or any information.

but the key is to remove the cursor and learn more about select statements, CASE statements, GROUP By's , and JOINS.

I hope this will help:

CREATE PROCEDURE ap_get_activity_by_country

@fromdate datetime

AS


select Countries.country,
country_count,
country_count_recent,
active_users/ country_count as percent_Active,
active_users,
download_count,
active_users_recent / country_count as percent_Active_recent
case when active_users <> 0 then download_count / active_users else 0 end as avg_downloads
from
(
select country, count(*) as country_count,
sum(case when user_create_time between @fromDate and getdate() then 1 else 0 end) as country_count_recent
from
smc_new_products.dbo.usr_smc
where country <> ''
group by country
) Countries
inner join
(
select country, count(distinct username) as active_users, count(username) as download_count from
smc_new_products.dbo.etechmodelrequests a
inner join
smc_new_products.dbo.usr_smc b
on
a.username = convert(varchar(50), b.user_id)
where requestdatetime between @fromdate and getdate()
and interfacename like '%download%'
group by country
)
b
on
countries.country = b.country


Also note: comparisions such as LIKE '%blah blah%' and JOINing based on converted fields (your username to varchar() conversion) can really slow things down because SQL can rarely use indexes for those sorts of things. If the interface name always starts with 'Download' then remove the first % and it will be much faster. better yet, add another field for that particular filter instead of relying on what is stored in a text field. That is, a field called "Download" that is 1 if it is a download or 0 otherwise.

Good luck. Please try to learn from my code; if it doens't work exactly, play with it and really try to get it to work yourself and you'll be much better off.

- Jeff

Edited by - jsmith8858 on 04/10/2003 15:29:44
Go to Top of Page

X002548
Not Just a Number

15586 Posts

Posted - 2003-04-10 : 15:29:48
How About the following:


SELECT a.Country
, Count(*) As Country_Count
, Sum(Case When b.user_create_time between @fromdate and getdate() Then 1 Else 0 End) As Country_Count_Recent
, Sum(Case When c.requestdatetime between @fromdate and getdate() and interfacename like '%download%' Then 1 Else 0 End) As Active_Users
From smc_new_products.dbo.usr_smc a
Left Join smc_new_products.dbo.usr b
On a.[user_id] = b.[user_id]
Left Join smc_new_products.dbo.etechmodelrequests c
On c.Username = convert(varchar(50), a.[user_id]



Brett

8-)
Go to Top of Page

MichaelP
Jedi Yak

2489 Posts

Posted - 2003-04-10 : 15:30:12
Get rid of the cursor, I'm sure that would help tremendously.
What you could do is do an INSERT INTO...SELECT on the distinct country query, and then JOIN those other queries to that table.

Something like this:
 
CREATE TABLE #DistinctCountries(Country VARCHAR(50))

INSERT INTO #DistinctCountries(Country)
SELECT distinct(country) FROM smc_new_products.dbo.usr_smc
WHERE country <>''



I'm not 100% sure on how to get those other queries to put the data into the table like you want, but it will probably require more INSERT INTO...SELECT stuff. I started to work it out, but it's not easy to do without your tables and some data in them.

Here was my work in progress:

CREATE TABLE #DistinctCountries(Country VARCHAR(50))

INSERT INTO #DistinctCountries(Country) VALUES('USA')
INSERT INTO #DistinctCountries(Country) VALUES('Canada')
INSERT INTO #DistinctCountries(Country) VALUES('England')

CREATE TABLE #Users(UserID INT IDENTITY(1,1), Country VARCHAR(50))

INSERT INTO #Users(Country) VALUES('USA')
INSERT INTO #Users(Country) VALUES('USA')
INSERT INTO #Users(Country) VALUES('USA')
INSERT INTO #Users(Country) VALUES('USA')

INSERT INTO #Users(Country) VALUES('Canada')
INSERT INTO #Users(Country) VALUES('Canada')
INSERT INTO #Users(Country) VALUES('Canada')

INSERT INTO #Users(Country) VALUES('England')
INSERT INTO #Users(Country) VALUES('England')

SELECT u.Country, count(*) AS DistinctUsersPerCountry
FROM #Users u
INNER JOIN #DistinctCountries dc ON dc.Country = u.Country
GROUP BY u.Country

DROP TABLE #Users
DROP TABLE #DistinctCountries


Michael

<Yoda>Use the Search page you must. Find the answer you will.</Yoda>
Go to Top of Page

jsmith8858
Dr. Cross Join

7423 Posts

Posted - 2003-04-10 : 15:32:03
Oh, one more thing:

quote:

if @active_users>0
Begin
Select @percent_active=(@active_users/@country_count)
end
else
Begin
select @percent_active=0
end



there is no need for the IF in your code; 0 divided by anything is 0. Normally in these cases you check the denominator to make sure it's not zero, NOT the numerator as you are doing. That is because anything divided BY 0 is an ERROR and needs to be handled.

- Jeff
Go to Top of Page

label
Posting Yak Master

197 Posts

Posted - 2003-04-10 : 15:57:12
Thanks for all your replies.

I'm currently running through your suggestions and trying to implement the fastest solution.

Go to Top of Page
   

- Advertisement -