Create Table dbo.T1Ar datiem (T1 = 3 ieraksti, T2 = 10000 ieraksti):
(
T1ID int primary key identity,
Value varchar(50)
)
Go
Create Table dbo.T2
(
T2ID int primary key identity,
T1ID int foreign key references dbo.T1 (T1ID),
Value char(5000)
)
-- SQL 2008 sintakseIzpildu šādu komandu komplektu:
set NoCount On;
Insert Into T1 (Value) Values ('jo'), ('jo 2'), ('jojo 2');
declare @i int = 0;
while @i < 10000
Begin
Insert into dbo.T2 Values(1, @i);
Set @i += 1;
End
Insert Into T1 Values ('Jauna vērtība');Vai redzi problēmu??
Delete T1 Where Value = 'Jauna vērtība';
Atbilde (publicēta 2012-08-06)
Patiesībā var saskatīt pat vairākas problēmas.
- Galvenā problēma: dzēšot T1 tabulas rindu (1 no 4 ierakstiem), tiek pilnībā pārlasīta visa tabula T2 (10 000 ieraksti, gandrīz 80 MB datu). Tabulu T2 speciāli veidoju tā, lai tā būtu relatīvi liela.
Ārējās atslēgas esamība nozīmē datu integritāti, nevis indeksa izveidi, par to plašāk var lasīt Ierobežojumi (Constraints). Problēmu ir viegli konstatēt izmantojot Vaicājuma IO statistiku.
Laižot piemēru visdrīzāk problēmu nejūt, jo dati atrodas operatīvajā atmiņā. Lai nosimulētu situāciju kad dati tiek nolasīti no diska, pēc insert komandām var izmantot komandas:
CHECKPOINT; -- saglabā datus fiziski uz diska
Problēmu varētu atrisināt izveidojot indeksu:
DBCC DROPCLEANBUFFERS; -- iztīra buferi! Nav labi darīt uz produkcijas servera
create index ix_t1id on dbo.t2 (t1id asc)
- Citas lietas, ko varēja pamanīt:
- Tabulā T2 kolonna "Value" datu tips ir char(5000), bet reāli glabā int vērtību (šeit, protams, tas ir speciāli, lai tabulas izmērs būtu lielāks);
- Komentāros bija piezīme, ka daudz insert komandas. Taisnība, ātrāka būtu datu ielāde, ja tiktu uzreiz ielādēta "kaudze" ar rindām, piemēram (arī šo iespējams paātrināt):
Insert into dbo.T2
Select Top (10000) 1,
ROW_NUMBER() Over (Order By so1.object_id)
From sys.all_objects so1
cross join sys.all_objects so2 - Labā prakse ir norādīt kolonnas aiz Insert Into dbo.T2; Labāk būtu:
Insert into dbo.T2 (T1ID, Value) Values(1, @i);
- Ja kaut kas ir vēl darāms ar ievietoto rindu, tad labāk iegūt tās identifikatoru- Kāda vērtība tika ielikta Identity laukā? (nevis atlasīt rindu pēc ievietotās vērtības, kas šajā gadījumā izsauc pilnu tabulas T1 pārlasīšanu):
Insert Into T1 Values ('Jauna vērtība');
Delete T1 Where T1ID = SCOPE_IDENTITY();
Un paldies tiem, kas padomāja un īpaši tiem, kas arī atbildēja :).
es neredzu. pat nepaslinkoju izpildīt visus skriptus. bez pārsteigumiem, izpildījās, neko neparastu nepamanīju.
AtbildētDzēstVēl kādu brīsniņu pagaidīšu līdz atbildēšanai, varbūt tomēr kāds variants izskanēs.
DzēstEs ne par tēmu - par SQL server neko daudz nezinu, bet tik un tā - 10 000 vērtību pievienošanai jāizmanto 10 000 query!? Iekšēji apraudājos.
AtbildētDzēstŠajā gadījumā tā ir testa datu ielāde ilustrācijai, tas šķiet pieņemami.
DzēstBet tās 10 000 rindas ir virziens kurā var domāt, mēģinot ieraudzīt problēmu.
emm, pareizā atbilde būs?
AtbildētDzēstDzēšot T1 tabulas rindu (1 no 4 ierakstiem), tiek pilnībā pārlasīta visa tabula T2 (10 000 ieraksti, gandrīz 80 MB datu).
DzēstTā arī ir atbilde, ko uzskatu par "pareizo", lai arī īpašos gadījumos tā var arī nebūt "pareizā" atbilde.