none
Datenbankzugriff optimieren RRS feed

  • 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

    Samstag, 20. September 2014 17:43

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

    Samstag, 20. September 2014 19:48
  • 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
    Montag, 29. September 2014 07:15

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

    Samstag, 20. September 2014 19:48
  • 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

    Sonntag, 21. September 2014 09:00
  • 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
    Montag, 29. September 2014 07:15
  • Hallo Klaus,

    das ist schön für Dich.

    Ebenso wohl auch, dass Du nie wieder Antworten von mir wirst lesen müssen.

    Gruß Elmar

    Montag, 29. September 2014 07:54
  • 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.

    Montag, 6. Oktober 2014 06:57
    Administrator
  • Hallo Dimitar,

    ich hab nur andere Indiz gesetzt ohne mein Programm zu ändern.

    Gruß Klaus

    Montag, 6. Oktober 2014 14:39