Benutzer mit den meisten Antworten
Datenbankzugriff optimieren

Frage
-
Hallo,
kann man den Datenbankzugriff noch optimieren?
Ablaufbeschreibung:
Abfragen, ob der Datensatz schon vorhanden ist.
Wenn ja - Feld "Anzahl" +1.
Wenn nein - Datensatz einfügen.
Die Daten sind alle Ganzzahlen.
Danke, Gruß Klaus
'Abfragen ob der Datensatz schon vorhanden ist Anzahl = 0 cmd10.Parameters.Clear() cmd10.CommandText = "SELECT COUNT (*) As Anzahl FROM DATENaus WHERE Z1 = @Z1 and Z2 = @Z2 and Z3 = @Z3 and Z4 = @Z4 and Z5 = @Z5 and Z6 = @Z6 and Z7 = @Z7 and Z8 = @Z8 and Z9 = @Z9 and Z10 = @Z10" cmd10.Parameters.AddWithValue("@Z1", Z1) cmd10.Parameters.AddWithValue("@Z2", Z2) cmd10.Parameters.AddWithValue("@Z3", Z3) cmd10.Parameters.AddWithValue("@Z4", Z4) cmd10.Parameters.AddWithValue("@Z5", Z5) cmd10.Parameters.AddWithValue("@Z6", Z6) cmd10.Parameters.AddWithValue("@Z7", Z7) cmd10.Parameters.AddWithValue("@Z8", Z8) cmd10.Parameters.AddWithValue("@Z9", Z9) cmd10.Parameters.AddWithValue("@Z10", Z10) Kombi = Convert.ToInt32(cmd10.ExecuteScalar()) 'Wenn Datensatz vorhanden - Anzahl +1 If Kombi = 1 Then cmd10.Parameters.Clear() cmd10.CommandText = "SELECT TOP 1 * FROM DATENaus WHERE Z1 = @Z1 and Z2 = @Z2 and Z3 = @Z3 and Z4 = @Z4 and Z5 = @Z5 and Z6 = @Z6 and Z7 = @Z7 and Z8 = @Z8 and Z9 = @Z9 and Z10 = @Z10" cmd10.Parameters.AddWithValue("@Z1", Z1) cmd10.Parameters.AddWithValue("@Z2", Z2) cmd10.Parameters.AddWithValue("@Z3", Z3) cmd10.Parameters.AddWithValue("@Z4", Z4) cmd10.Parameters.AddWithValue("@Z5", Z5) cmd10.Parameters.AddWithValue("@Z6", Z6) cmd10.Parameters.AddWithValue("@Z7", Z7) cmd10.Parameters.AddWithValue("@Z8", Z8) cmd10.Parameters.AddWithValue("@Z9", Z9) cmd10.Parameters.AddWithValue("@Z10", Z10) Dim dr10 As Common.DbDataReader = cmd10.ExecuteReader() If (dr10.Read()) Then Anzahl = dr10("Anzahl") ID = dr10("ID") End If dr10.Close() dr10.Dispose() Anzahl = Anzahl + 1 cmd10.Parameters.Clear() cmd10.CommandText = "UPDATE DATENaus SET Anzahl = @Anzahl WHERE ID = @ID " cmd10.Parameters.AddWithValue("@ID", ID) cmd10.Parameters.AddWithValue("@Anzahl", Anzahl) cmd10.ExecuteNonQuery() Else 'Datensatz anlegen Anzahl = 1 cmd10.Parameters.Clear() cmd10.CommandText = "INSERT DATENaus (Anzahl, Z1, Z2, Z3, Z4, Z5, Z6, Z7, Z8, Z9, Z10) VALUES (@Anzahl, @Z1, @Z2, @Z3, @Z4, @Z5, @Z6, @Z7, @Z8, @Z9, @Z10)" cmd10.Parameters.AddWithValue("@Z1", Z1) cmd10.Parameters.AddWithValue("@Z2", Z2) cmd10.Parameters.AddWithValue("@Z3", Z3) cmd10.Parameters.AddWithValue("@Z4", Z4) cmd10.Parameters.AddWithValue("@Z5", Z5) cmd10.Parameters.AddWithValue("@Z6", Z6) cmd10.Parameters.AddWithValue("@Z7", Z7) cmd10.Parameters.AddWithValue("@Z8", Z8) cmd10.Parameters.AddWithValue("@Z9", Z9) cmd10.Parameters.AddWithValue("@Z10", Z10) cmd10.Parameters.AddWithValue("@Anzahl", Anzahl) cmd10.ExecuteNonQuery() End If
Antworten
-
Hallo,
naja, 10 Spalten als Schlüssel sind schon ziemlich deftig. Was man der Tabelle zusätzlich spendieren sollte wäre eine Identitätsspalte, damit Lookups etwas zügiger ablaufen können.
Was nicht notwendig und auch nicht zielführend ist, wäre Dein anfängliches Zählen - in einer Mehrplatzumgebung geht das womöglich daneben, weil sich die Zahl verändert hat. Sinnvoller: Mach ein UPDATE und schlägt der fehl (@@ROWCOUNT = 0) füge eine neue Zeile ein.
In einer Anweisung geht es über MERGE (ab SQL Server 2008). Ein Beispiel - verpackt in einer Prozedur - , aber man kann MERGE auch direkt in einbetten:
USE tempdb; GO CREATE TABLE dbo.DATENaus ( ID int IDENTITY(1, 1) NOT NULL, Z1 int NOT NULL, Z2 int NOT NULL, Z3 int NOT NULL, Z4 int NOT NULL, Z5 int NOT NULL, Z6 int NOT NULL, Z7 int NOT NULL, Z8 int NOT NULL, Z9 int NOT NULL, Z10 int NOT NULL, Anzahl int NOT NULL CONSTRAINT DF_DATENaus_Anzahl DEFAULT (0), CONSTRAINT PK_DATENaus PRIMARY KEY (ID), -- scheusslich aber derzeit notwendig CONSTRAINT UK_DATENaus UNIQUE (Z1, Z2, Z3, Z4, Z5, Z6, Z7, Z8, Z9, Z10)); GO CREATE PROCEDURE dbo.DATENaus_Anzahl ( @Z1 int, @Z2 int, @Z3 int, @Z4 int, @Z5 int, @Z6 int, @Z7 int, @Z8 int, @Z9 int, @Z10 int, @Anzahl int ) AS SET NOCOUNT ON; MERGE DATENaus AS T USING (SELECT @Z1, @Z2, @Z3, @Z4, @Z5, @Z6, @Z7, @Z8, @Z9, @Z10, @Anzahl) AS S (Z1, Z2, Z3, Z4, Z5, Z6, Z7, Z8, Z9, Z10, Anzahl) ON T.Z1 = S.Z1 AND T.Z2 = S.Z2 AND T.Z3 = S.Z3 AND T.Z4 = S.Z4 AND T.Z5 = S.Z5 AND T.Z6 = S.Z6 AND T.Z7 = S.Z7 AND T.Z8 = S.Z8 AND T.Z9 = S.Z9 AND T.Z10 = S.Z10 WHEN MATCHED THEN UPDATE SET Anzahl = t.Anzahl + s.Anzahl WHEN NOT MATCHED THEN INSERT (Z1, Z2, Z3, Z4, Z5, Z6, Z7, Z8, Z9, Z10, Anzahl) VALUES (s.Z1, s.Z2, s.Z3, s.Z4, s.Z5, s.Z6, s.Z7, s.Z8, s.Z9, s.Z10, s.Anzahl) OUTPUT $action AS Action, inserted.ID, inserted.Anzahl; GO EXEC dbo.DATENaus_Anzahl 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100; EXEC dbo.DATENaus_Anzahl 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1; EXEC dbo.DATENaus_Anzahl 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100; EXEC dbo.DATENaus_Anzahl 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, -1; EXEC dbo.DATENaus_Anzahl 3, 2, 3, 4, 5, 6, 7, 8, 9, 10, 33; SELECT * FROM DATENaus; GO DROP PROC dbo.DATENaus_Anzahl; DROP TABLE dbo.DATENaus; GO
Als Nebeneffekt liefert Dir die angehängte OUTPUT Klausel die ausgeführte Aktion, die zugehörige ID und die (neue) Anzahl. In ADO.NET musst Du ExecuteReader verwenden, um die Daten für alle Spalten zu erhalten. Gespeicherte Prozeduren werden über CommandType.Procedure ausgeführt, in CommandText steht dann der Name der Prozedur (ohne EXEC)
Gruß Elmar
- Als Antwort vorgeschlagen Andreas.WolterMicrosoft employee Samstag, 20. September 2014 23:07
- Als Antwort markiert Dimitar DenkovMicrosoft contingent staff, Administrator Montag, 6. Oktober 2014 06:54
-
Danke!
Ich habe eine andere Lösung gefunden.
Läuft jetz mit bis über 130000 Select/Min.
Danke, Gruß Klaus
- Als Antwort markiert BlauesBlatt Montag, 29. September 2014 07:16
Alle Antworten
-
Hallo,
naja, 10 Spalten als Schlüssel sind schon ziemlich deftig. Was man der Tabelle zusätzlich spendieren sollte wäre eine Identitätsspalte, damit Lookups etwas zügiger ablaufen können.
Was nicht notwendig und auch nicht zielführend ist, wäre Dein anfängliches Zählen - in einer Mehrplatzumgebung geht das womöglich daneben, weil sich die Zahl verändert hat. Sinnvoller: Mach ein UPDATE und schlägt der fehl (@@ROWCOUNT = 0) füge eine neue Zeile ein.
In einer Anweisung geht es über MERGE (ab SQL Server 2008). Ein Beispiel - verpackt in einer Prozedur - , aber man kann MERGE auch direkt in einbetten:
USE tempdb; GO CREATE TABLE dbo.DATENaus ( ID int IDENTITY(1, 1) NOT NULL, Z1 int NOT NULL, Z2 int NOT NULL, Z3 int NOT NULL, Z4 int NOT NULL, Z5 int NOT NULL, Z6 int NOT NULL, Z7 int NOT NULL, Z8 int NOT NULL, Z9 int NOT NULL, Z10 int NOT NULL, Anzahl int NOT NULL CONSTRAINT DF_DATENaus_Anzahl DEFAULT (0), CONSTRAINT PK_DATENaus PRIMARY KEY (ID), -- scheusslich aber derzeit notwendig CONSTRAINT UK_DATENaus UNIQUE (Z1, Z2, Z3, Z4, Z5, Z6, Z7, Z8, Z9, Z10)); GO CREATE PROCEDURE dbo.DATENaus_Anzahl ( @Z1 int, @Z2 int, @Z3 int, @Z4 int, @Z5 int, @Z6 int, @Z7 int, @Z8 int, @Z9 int, @Z10 int, @Anzahl int ) AS SET NOCOUNT ON; MERGE DATENaus AS T USING (SELECT @Z1, @Z2, @Z3, @Z4, @Z5, @Z6, @Z7, @Z8, @Z9, @Z10, @Anzahl) AS S (Z1, Z2, Z3, Z4, Z5, Z6, Z7, Z8, Z9, Z10, Anzahl) ON T.Z1 = S.Z1 AND T.Z2 = S.Z2 AND T.Z3 = S.Z3 AND T.Z4 = S.Z4 AND T.Z5 = S.Z5 AND T.Z6 = S.Z6 AND T.Z7 = S.Z7 AND T.Z8 = S.Z8 AND T.Z9 = S.Z9 AND T.Z10 = S.Z10 WHEN MATCHED THEN UPDATE SET Anzahl = t.Anzahl + s.Anzahl WHEN NOT MATCHED THEN INSERT (Z1, Z2, Z3, Z4, Z5, Z6, Z7, Z8, Z9, Z10, Anzahl) VALUES (s.Z1, s.Z2, s.Z3, s.Z4, s.Z5, s.Z6, s.Z7, s.Z8, s.Z9, s.Z10, s.Anzahl) OUTPUT $action AS Action, inserted.ID, inserted.Anzahl; GO EXEC dbo.DATENaus_Anzahl 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100; EXEC dbo.DATENaus_Anzahl 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1; EXEC dbo.DATENaus_Anzahl 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100; EXEC dbo.DATENaus_Anzahl 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, -1; EXEC dbo.DATENaus_Anzahl 3, 2, 3, 4, 5, 6, 7, 8, 9, 10, 33; SELECT * FROM DATENaus; GO DROP PROC dbo.DATENaus_Anzahl; DROP TABLE dbo.DATENaus; GO
Als Nebeneffekt liefert Dir die angehängte OUTPUT Klausel die ausgeführte Aktion, die zugehörige ID und die (neue) Anzahl. In ADO.NET musst Du ExecuteReader verwenden, um die Daten für alle Spalten zu erhalten. Gespeicherte Prozeduren werden über CommandType.Procedure ausgeführt, in CommandText steht dann der Name der Prozedur (ohne EXEC)
Gruß Elmar
- Als Antwort vorgeschlagen Andreas.WolterMicrosoft employee Samstag, 20. September 2014 23:07
- Als Antwort markiert Dimitar DenkovMicrosoft contingent staff, Administrator Montag, 6. Oktober 2014 06:54
-
Hallo Elmar,
Danke für deine Antwort.
Verstehen tu ich sie allerdings nicht.
Meine Datenbank hat eine Identitätsspalte (ID).
Die Spalte Anzahl bezieht sich darauf, wie oft der einzelne Datensatz vorkommt.
Die Daten in den Spalten Z1-Z10 haben keine Nullwerte und sind Ganzzahlen.
Ich benutze VB 2010 Express.
Danke, Gruß Klaus
-
Danke!
Ich habe eine andere Lösung gefunden.
Läuft jetz mit bis über 130000 Select/Min.
Danke, Gruß Klaus
- Als Antwort markiert BlauesBlatt Montag, 29. September 2014 07:16
-
Hallo Klaus,
Würdest Du die andere Lösung ans Licht bringen, damit auch andere davon Gebrauch machen können, wenn sie das gleiche Ergebnis erzielen wollen?
Grüße, Dimitar
Bitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip „IT-Pros helfen IT-Pros“ beruht, kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können.