September 15, 2005 at 12:39 pm
Hi SQL Server Central. The following script takes at least a couple of hours to run and I'm wondering if anyone has any ideas on how I can improve on the efficiency. It produces all capital letters between AAAAA and ZZZZZ which should be around 11 million rows.
Thanks,
Terry
==================================
CREATE TABLE [dbo].[tblitAAAAA] (
[itAAAAA] [char] (5) NOT NULL
) ON [PRIMARY]
GO
declare @position tinyint, @string char(5)
set @string = 'AAAAA'
set @position = 5
while ASCII(SUBSTRING(@string, @position-4, 1))<91 begin --90 is ASCII for Z
while ASCII(SUBSTRING(@string, @position-3, 1))<91 begin
while ASCII(SUBSTRING(@string, @position-2, 1))<91 begin
while ASCII(SUBSTRING(@string, @position-1, 1))<91 begin
while ASCII(SUBSTRING(@string, @position, 1))<91 begin
insert tblitAAAAA (itAAAAA)
values (@string)
set @string=CHAR(ASCII(SUBSTRING(@string, @position-4, 1)))+CHAR(ASCII(SUBSTRING(@string, @position-3, 1)))+CHAR(ASCII(SUBSTRING(@string, @position-2, 1)))+CHAR(ASCII(SUBSTRING(@string, @position-1, 1)))+char(ASCII(SUBSTRING(@string, @position, 1))+1)
end
set @string=CHAR(ASCII(SUBSTRING(@string, @position-4, 1)))+CHAR(ASCII(SUBSTRING(@string, @position-3, 1)))+CHAR(ASCII(SUBSTRING(@string, @position-2, 1)))+CHAR(ASCII(SUBSTRING(@string, @position-1, 1))+1)+'A'
end
set @string=CHAR(ASCII(SUBSTRING(@string, @position-4, 1)))+CHAR(ASCII(SUBSTRING(@string, @position-3, 1)))+CHAR(ASCII(SUBSTRING(@string, @position-2, 1))+1)+'A'+'A'
end
set @string=CHAR(ASCII(SUBSTRING(@string, @position-4, 1)))+CHAR(ASCII(SUBSTRING(@string, @position-3, 1))+1)+'A'+'A'+'A'
end
set @string=CHAR(ASCII(SUBSTRING(@string, @position-4, 1))+1)+'A'+'A'+'A'+'A'
end
September 15, 2005 at 12:50 pm
This generates 11881376 rows in 71 seconds (without sorting) on a slow server
Select dtA.Frst + dtB.Sec + dtC.ThD + dtD.Fourth + dtE.Fifth As GenList FROM
(Select CHAR(PkNumber) as Frst from dbo.Numbers where PkNumber between 65 and 90) dtA
cross join
(Select CHAR(PkNumber) as Sec from dbo.Numbers where PkNumber between 65 and 90) dtB
cross join
(Select CHAR(PkNumber) as Thd from dbo.Numbers where PkNumber between 65 and 90) dtC
cross join
(Select CHAR(PkNumber) as Fourth from dbo.Numbers where PkNumber between 65 and 90) dtD
cross join
(Select CHAR(PkNumber) as Fifth from dbo.Numbers where PkNumber between 65 and 90) dtE
--Order by GenList --the sort accounts for 96% of the work load...
here's the script for the numbers table :
IF Object_id('Numbers') > 0
DROP TABLE dbo.Numbers
GO
CREATE TABLE dbo.Numbers (PkNumber int identity(1,1) primary key clustered, dude bit null)
GO
INSERT INTO dbo.Numbers (dude)
SELECT NULL FROM (SELECT TOP 100 NULL AS A FROM master.dbo.spt_values) dt100 cross join (SELECT TOP 80 null AS A FROM master.dbo.spt_values) dt80
GO
ALTER TABLE dbo.Numbers
DROP COLUMN dude
GO
--Select min(PkNumber) as MinA, max(PkNumber) as MaxA from dbo.Numbers
--1, 8000
GO
--DROP TABLE dbo.Numbers
September 15, 2005 at 1:00 pm
Your current statement performs 11,881,376 seperate insert statements and for each insert, space management and transaction log writes must be performed. A single statement that inserts all of the rows at once will probable be faster.
For 4 characters, this runs in less than one minute for 456,976 rows:
insert tblitAAAAA (itAAAAA)
select char(p1.seq) + char(p2.seq) + char(p3.seq) + char(p4.seq)
from sequences as P1
,sequences as P2
,sequences as P3
,sequences as P4
wherep1.seq between 65 and 90
and p2.seq between 65 and 90
and p3.seq between 65 and 90
and p4.seq between 65 and 90
Since you probably have some resource limits, such as disk space for the transaction log, you might want to run the sql statement 26 times with the last character value set in the WHILE loop such as:
declare @l integer
set @l = 64
while @l < 90
begin
set @l = @l + 1
insert tblitAAAAA (itAAAAA)
select char(p1.seq) + char(p2.seq) + char(p3.seq) + char(p4.seq)
+ char(@l)
from sequences as P1
,sequences as P2
,sequences as P3
,sequences as P4
wherep1.seq between 65 and 90
and p2.seq between 65 and 90
and p3.seq between 65 and 90
and p4.seq between 65 and 90
END
The sequences table:
-- drop table Sequences
set nocount on
set xact_abort on
create table Sequences
( Seq smallint not null
, constraint Sequences_PK primary key (Seq) )
-- Create a new table to turn columns into rows or rows into columns
declare @SmallIntMaxinteger
,@SeqMaxinteger
set@SmallIntMax= power(2,15) - 1
-- Populate the Sequences table:
-- zero is also useful.
Insert into Sequences (Seq) values (0)
Insert into Sequences (Seq) values (1)
-- Now repeat the following insert 10 times to get 1024 sequence Sequences
set @SeqMax = 1
while @SeqMax < @SmallIntMax
begin
Insert into Sequences
SELECT NewSeq
FROM (select Seq + @SeqMax + 1 AS NewSeq
from Sequences
) as S
Order by NewSeq
select @SeqMax = max(Seq) from Sequences
end
go
select 'Largest Seq is ' , max(Seq) from Sequences
-- Check for gaps
select top 1 * from sequences p
where seq < 32767
and not exists
(select 1 from sequences as n where n.seq = p.seq + 1 )
-- Do not rebuild the index !!!
go
SQL = Scarcely Qualifies as a Language
September 15, 2005 at 1:08 pm
just ran some more test inserting in a temp table
--17576 rows in 11 seconds
--456976 rows in 43 seconds
ran out of space in tempdb for the final pass (after almost 9 minutes which should be about 50% done)
September 15, 2005 at 1:15 pm
if resources allow it use SELECT INTO instead of insert for speed
* Noel
September 15, 2005 at 1:16 pm
Good point... assuming you can afford a lock on the system tables for a few minutes.
September 15, 2005 at 1:20 pm
I don't think this type of operation is meant to be performed a lot of times of very often that's why I thought about select into
* Noel
September 15, 2005 at 1:28 pm
Obviously ! Here are the results on a slow server (in production) :
Select TOP 100 PERCENT
dtA.Frst
+ dtB.Sec
+ dtC.ThD
+ dtD.Fourth
+ dtE.Fifth
As GenList
INTO dbo.TestInsertInto
FROM
(Select CHAR(PkNumber) as Frst from dbo.Numbers where PkNumber between 65 and 90) dtA
cross join
(Select CHAR(PkNumber) as Sec from dbo.Numbers where PkNumber between 65 and 90) dtB
cross join
(Select CHAR(PkNumber) as Thd from dbo.Numbers where PkNumber between 65 and 90) dtC
cross join
(Select CHAR(PkNumber) as Fourth from dbo.Numbers where PkNumber between 65 and 90) dtD
cross join
(Select CHAR(PkNumber) as Fifth from dbo.Numbers where PkNumber between 65 and 90) dtE
Order by GenList --the sort accounts for 96% of the work load...
GO
DROP TABLE TestInsertInto
--17576 rows in 1 seconds
--456976 rows in 4 seconds
--11881376 rows in 173 seconds
October 19, 2005 at 10:17 am
Thanks to all who answered my question here!
Much appreciated.
Viewing 9 posts - 1 through 8 (of 8 total)
You must be logged in to reply to this topic. Login to reply