July 7, 2005 at 8:58 am
HTH.
July 7, 2005 at 8:29 pm
A set solution vs an equivalent cursor solution is at least 3 times faster, and usually 10 times faster. That's why a set solution (and the internal engine that makes the necessary search) should always be faster than a one by one procedural-solution.
I can't only imagine a cursor solution faster than a set solution, if the tables involved are frequently blocked or does not have the proper index defined.
July 7, 2005 at 11:06 pm
The one and only case I'm aware of is this one :
Let's say you want to get the nth line of a big query, it's sometimes faster to open the query in a cursor and use the goto line# (sorry forgot the actual name call). This can be faster because you often result to some sort of unequal joing with group by and count(*) to generate the row number which takes longer than to just query the table once and goto the right line (faster than create table/insert into + select too).
July 8, 2005 at 12:29 am
Remi wrote:
Here's my thinking : Don't use cursors, ever. Then if you find a situation where a cursor is faster than a set based approach or there's no set based approach (some rare admin task), then go for it. But I assure you that it's not gonna happen often.
Now knowing what you mean by "set based approach", I agree that in many cases this can replace cursors and will be faster. But I am not convinced that it can be used as often as you describe. How would you write a stored procedure, with input parameter @n int, that inserts into a table t(id int) all integers between 1 and @n - without using a cursor (or a loop)?
July 8, 2005 at 12:43 am
How about another case.
I've got to send out the same email message to two different addresses
EmailAddressTable me@here you@thereMessageTable The job you wanted done is complete
I've got a procedure called usp_SendTheEmail that takes two parameters @To varchar(250) & @Msg varchar(150)
And this shouldn't count towards your post count
--------------------
Colt 45 - the original point and click interface
July 8, 2005 at 6:39 am
Just a theory...
How about using blind carbon copy .
I know that there are other situations where you have no choice but they should be few and far apart. But that could still use a loop instead of a cursor (not that a loop is really faster anyways).
July 8, 2005 at 6:55 am
"Now knowing what you mean by "set based approach", I agree that in many cases this can replace cursors and will be faster. But I am not convinced that it can be used as often as you describe. How would you write a stored procedure, with input parameter @n int, that inserts into a table t(id int) all integers between 1 and @n - without using a cursor (or a loop)?"
If you have something harder than this, please post, we love to have new challenges :
Declare @Qty as int
SET @Qty = 7500
create table #a (id int identity(1,1) primary key, dude int not null)
SET ROWCOUNT @Qty
GO
Insert into #a (dude)
Select O.number from master.dbo.spt_values O cross join master.dbo.spt_values O2
/*this takes a long time because it generates 532900 records in my db... A better table choice will speed this up a lot (if you don't expect to need more than 20k records for exemple, then you just create a table with 142 records and cross join to itself, this would run 26 times faster >> ±0.06 sec)*/
GO
SET ROWCOUNT 0 --unlimited
GO
alter table #a
drop column dude
GO
select min(id), max(id) from #a
GO
drop table #a
GO
--this still run in less than 2 secs on a slow server
July 8, 2005 at 7:40 am
I have a good one for you...
I have a table with 102 columns. The name of each column is an agency. The table has 59,000 rows. I have to look at each column in each row and if the column is TRUE (bit) then insert an entry into another table with the PK of the row and the PK of the associated agency entry from the agency table based on the agency name=column name. So that's 6M cells to process and it takes about 2 hours.
Would I have even designed it that way in the first place? Heck no!! I inherited it from someone and the entire app (Access front-end, SQL back-end, ewwwww!!) is based on this table structure. Nobody wants to pay to have it redone correctly.
I can post the code I'm using to do it if anyone really wants a challenge
July 8, 2005 at 7:42 am
Oh, and on the Email thing you can use COALESCE to create a comma-delimited string of all the entries in your email table, then use that as your To or BCC. I do that all the time. There's a good post on the board here somewhere on using COALESCE to create a comma-delimited string. You should be able to find it with search.
July 8, 2005 at 7:44 am
I post this code all the time :
IF Object_id('ListTableColumns') > 0
DROP FUNCTION ListTableColumns
GO
CREATE FUNCTION dbo.ListTableColumns (@TableID as int)
RETURNS varchar(8000)
AS
BEGIN
Declare @Items as varchar(8000)
SET @Items = ''
SELECT
@Items = @Items + C.Name + ', '
FROMdbo.SysColumns C
WHEREC.id = @TableID
AND OBJECTPROPERTY(@TableID, 'IsTable') = 1
ORDER BYC.Name
SET @Items = LEFT(@Items, ABS(DATALENGTH(@Items) - 2))
RETURN @Items
END
GO
Select dbo.ListTableColumns(Object_id('SysObjects'))
--base_schema_ver, cache, category, crdate, deltrig, ftcatid, id, indexdel, info, instrig, name, parent_obj, refdate, replinfo, schema_ver, seltrig, stats_schema_ver, status, sysstat, type, uid, updtrig, userstat, version, xtype
DROP FUNCTION ListTableColumns
July 8, 2005 at 7:45 am
Shoot.
July 8, 2005 at 7:47 am
I have no trouble getting the column names from syscolumns, it's the iterating over the actual data columns (102) times 59,000 rows and determining for each one whether or not I need to insert a record into the association table...
July 8, 2005 at 7:51 am
Here's the code. I'm working on getting the CarID into the table variable up front so I don't do that repetitively in the second WHILE loop. If anyone can figure out how to do the code in the WHILE loop (minus the select on CarID), or any other way to speed this up I would be ecstatic!
-------------------------------------------------------------------------
DECLARE @maxcol int
DECLARE @maxid int
DECLARE @curid int
DECLARE @oldid int
DECLARE @ColID int
DECLARE @colname nvarchar(100)
DECLARE @carid int
DECLARE @count float
DECLARE @cols table(cid int identity, colname nvarchar(100))
SET NOCOUNT ON
SET @count = 1
TRUNCATE TABLE APPOINTMENTS
SELECT @maxcol=max(ordinal_position)-2 FROM information_schema.columns
WHERE table_name='2004 UIL Prospects Appointments'
SELECT @maxid=max(ProspectID) FROM [2004 UIL Prospects Appointments]
SELECT @curid=min(ProspectID) FROM [2004 UIL Prospects Appointments]
SET @oldid=@curid
set @ColID=11
While @ColID <=@maxcol BEGIN
insert into @cols
Select column_name FROM information_schema.columns
WHERE table_name=N'2004 UIL Prospects Appointments'
set @ColID=@ColID + 1
END
WHILE @curid<=@maxid BEGIN
IF @count/100=ceiling(@count/100) PRINT CAST(@count as varchar(8))
SET @ColID=11
WHILE @ColID <= @maxcol BEGIN
SELECT @colname=colname from @cols where cid=@ColID-10
SELECT @carid=carid FROM Carriers WHERE Carrier=@colname
INSERT INTO Appointments (ID, CarID) VALUES(@curid, @carid)
SET @ColID = @ColID + 1
END
SELECT @curid=min(ProspectID) FROM [2004 UIL Prospects Appointments]
WHERE ProspectID>@oldid
SET @oldid=@curid
SET @count = @count + 1
END
July 8, 2005 at 7:54 am
Can you give the rest of the detais??
Sample data/ddl and output in the other tables would really help a lot .
July 8, 2005 at 8:01 am
The DDL for the simple tables:
CREATE TABLE [dbo].[Appointments] (
[ID] [int] NULL ,
[CarID] [int] NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Carriers] (
[Carrier] [nvarchar] (255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[CarID] [int] NOT NULL
) ON [PRIMARY]
GO
The DDL for the big table that I have to iterate through:
CREATE TABLE [dbo].[2004 UIL Prospects Appointments] (
[ProspectID] [int] NOT NULL ,
[Agency] [nvarchar] (100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[Contact] [nvarchar] (100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[Address] [nvarchar] (100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[City] [nvarchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[State] [nvarchar] (5) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[Zip] [nvarchar] (15) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[Phone] [decimal](19, 0) NULL ,
[Fax] [decimal](19, 0) NULL ,
[HIG Match] [nvarchar] (1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[1st Auto] [bit] NOT NULL ,
[Accident Fund] [bit] NOT NULL ,
[ACUITY] [bit] NOT NULL ,
[Allied] [bit] NOT NULL ,
[Amerisure] [bit] NOT NULL ,
[ASI] [bit] NOT NULL ,
[Atlantic Mutual] [bit] NOT NULL ,
[Austin Mutual] [bit] NOT NULL ,
[Badger] [bit] NOT NULL ,
[Barnstable] [bit] NOT NULL ,
[Beacon] [bit] NOT NULL ,
[Bituminous] [bit] NOT NULL ,
[Blue Ridge] [bit] NOT NULL ,
[Brethren Mutual] [bit] NOT NULL ,
[Briarcreek] [bit] NOT NULL ,
[Buckeye] [bit] NOT NULL ,
[Bunker Hill] [bit] NOT NULL ,
[Calif Insurance Group] [bit] NOT NULL ,
[Cameron] [bit] NOT NULL ,
[Casco] [bit] NOT NULL ,
[Central Mutual] [bit] NOT NULL ,
[Chubb] [bit] NOT NULL ,
[Cincinnati Financial] [bit] NOT NULL ,
[C N A] [bit] NOT NULL ,
[Colorado Casualty] [bit] NOT NULL ,
[Columbia] [bit] NOT NULL ,
[Commerce] [bit] NOT NULL ,
[Continental Western] [bit] NOT NULL ,
[crop insurer] [bit] NOT NULL ,
[Cumberland] [bit] NOT NULL ,
[Donegal] [bit] NOT NULL ,
[Encompass] [bit] NOT NULL ,
[Erie] [bit] NOT NULL ,
[Erie and Niagara] [bit] NOT NULL ,
[Everett Cash Mutual] [bit] NOT NULL ,
[FAMI] [bit] NOT NULL ,
[Farmers and Merchanics] [bit] NOT NULL ,
[Farmers Mutual of Nebraska] [bit] NOT NULL ,
[Financial Pacific] [bit] NOT NULL ,
[Finger Lakes] [bit] NOT NULL ,
[Firemans Fund] [bit] NOT NULL ,
[Foremost] [bit] NOT NULL ,
[Fremont Insurance] [bit] NOT NULL ,
[General Casualty] [bit] NOT NULL ,
[GMAC] [bit] NOT NULL ,
[GuideOne] [bit] NOT NULL ,
[Hanover] [bit] NOT NULL ,
[Harleysville] [bit] NOT NULL ,
[Hartford] [bit] NOT NULL ,
[Hastings Mutual] [bit] NOT NULL ,
[Hawaii Employers] [bit] NOT NULL ,
[IIABA] [bit] NOT NULL ,
[Iowa Mutual] [bit] NOT NULL ,
[Kansas Mutual] [bit] NOT NULL ,
[Lebananon] [bit] NOT NULL ,
[Liberty Northwest] [bit] NOT NULL ,
[Madison Mutual] [bit] NOT NULL ,
[Marysville Mutual] [bit] NOT NULL ,
[MD Injured Works fund] [bit] NOT NULL ,
[Merchants] [bit] NOT NULL ,
[Mercury] [bit] NOT NULL ,
[Miami Mutual] [bit] NOT NULL ,
[MICOA] [bit] NOT NULL ,
[Midwest Family Mutual] [bit] NOT NULL ,
[Montgomery Insurance] [bit] NOT NULL ,
[MSA] [bit] NOT NULL ,
[Mutual Fire] [bit] NOT NULL ,
[NLC] [bit] NOT NULL ,
[Northern Neck] [bit] NOT NULL ,
[Ohio Casualty] [bit] NOT NULL ,
[OneBeacon] [bit] NOT NULL ,
[Oregon Mutual] [bit] NOT NULL ,
[Peninsula] [bit] NOT NULL ,
[Penn National] [bit] NOT NULL ,
[Pioneer State] [bit] NOT NULL ,
[PRAC] [bit] NOT NULL ,
[Preferred Mutual] [bit] NOT NULL ,
[PROG] [bit] NOT NULL ,
[Rockford Mutual] [bit] NOT NULL ,
[Rockwood Casualty] [bit] NOT NULL ,
[Safeco] [bit] NOT NULL ,
[Safety] [bit] NOT NULL ,
[SAIF] [bit] NOT NULL ,
[Secura] [bit] NOT NULL ,
[Selective] [bit] NOT NULL ,
[Southern Family] [bit] NOT NULL ,
[Southern Mutual] [bit] NOT NULL ,
[St Paul] [bit] NOT NULL ,
[State Auto] [bit] NOT NULL ,
[Superior] [bit] NOT NULL ,
[The Columbus OH Grange] [bit] NOT NULL ,
[Travelers] [bit] NOT NULL ,
[Tuscarora-Wayne] [bit] NOT NULL ,
[Unigard] [bit] NOT NULL ,
[Unitrin] [bit] NOT NULL ,
[West Bend] [bit] NOT NULL ,
[Western Reserve] [bit] NOT NULL ,
[Westfield] [bit] NOT NULL ,
[Wilson Mutual] [bit] NOT NULL ,
[Windsor] [bit] NOT NULL ,
[Wisconsin Mutual] [bit] NOT NULL ,
[Wolverine] [bit] NOT NULL ,
[Added] [bit] NOT NULL ,
[Undesirable] [bit] NOT NULL
) ON [PRIMARY]
GO
The columns starting with [1st Auto] and ending with [Wolverine] are the ones I have to scan.
Sample of Carriers:
1st Auto 1
Accident Fund 2
ACUITY 3
Allied 4
Amerisure 5
ASI 6
Atlantic Mutual 7
Austin Mutual 8
Badger 9
Barnstable 10
Sample of Appointments:
1 1
1 2
1 3
1 4
1 5
1 6
1 7
1 8
1 9
1 10
Sample of the big table:
1 A Kenai Alaska Insurance Agency NULL 5791 Kenai Spur Hwy Kenai AK 99611 9072834191 NULL N 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
2 Acordia of Alaska NULL 35681 Kenai Spur Hwy Soldotna AK 99699 9072622515 9072622646 N 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Viewing 15 posts - 16 through 30 (of 70 total)
You must be logged in to reply to this topic. Login to reply