Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Spalten ohne Varianzen (https://www.delphipraxis.net/180028-spalten-ohne-varianzen.html)

Mokus 17. Apr 2014 14:42

Datenbank: SQL • Version: XX • Zugriff über: MSSMS

Spalten ohne Varianzen
 
Hey hoy,

hab ein kleines SQL Statement geschribene,w elches alle Spalten ohne Varianz ausgegen soll ...

Problem ?
Fucking performance......

wenn wer auf das Script schaut und verbesserung habt, bitte melden ....


SQL-Code:
/* 
@Result vom dynamischen sql:
0 = NUR NULL WERTE
1 = VERSCHIEDENE WERTE
2 = EIN EINZIGER WERT DER NICHT NULL IST

*/

alter procedure GET_SPALTEN
as
begin
  set NOCOUNT on

  declare @Tab table (
    ID      INT identity(0, 1) primary key,
    TAB     NVARCHAR(MAX),
    SPALTE  NVARCHAR(MAX),
    TYP     NVARCHAR(MAX),
    WERT    NVARCHAR(MAX),
    ONLYNULL BIT,
    ROW     INT)

  declare @tabelle NVARCHAR(MAX)

  declare @debug INT = 0

  declare @Spalte NVARCHAR(MAX)

  declare @Typ NVARCHAR(MAX)

  declare @vorhanden SMALLINT

  declare @sql NVARCHAR(MAX)

  declare @params NVARCHAR(MAX)

  declare @einzigWert NVARCHAR(MAX)

  declare COURCHECK cursor FAST_FORWARD for
    (select
       TAB,
       SPALTE,
       TYP
     from  @Tab)

  insert into @Tab
              (TAB,
               SPALTE,
               TYP)
  (select
     SYS.TABLES.NAME,
     SYS.ALL_COLUMNS.NAME,
     SYS.TYPES.NAME
   from  SYS.TABLES
          join SYS.ALL_COLUMNS
            on SYS.ALL_COLUMNS.OBJECT_ID = SYS.TABLES.OBJECT_ID
          join SYS.TYPES
            on SYS.TYPES.USER_TYPE_ID = SYS.ALL_COLUMNS.USER_TYPE_ID
   where SYS.TABLES.TYPE = 'U')

  select
    NAME=SPACE(100),
    ROWS = 1000000,
    RESERVED=SPACE(255),
    DATA=SPACE(255),
    INDEX_SIZE=SPACE(255),
    UNUSED= SPACE(255)
  into  #TEMP
  -- dmv
  delete #TEMP

  declare @name VARCHAR(255)

  declare CRSTOUR cursor fast_forward for
    select
      NAME
    from  SYSOBJECTS
    where XTYPE = 'U' --order by name

  open CRSTOUR

  fetch NEXT from CRSTOUR into @name

  while ( @@fetch_status = 0 )
  begin
    insert into #TEMP
    execute SP_SPACEUSED
      @name

    fetch NEXT from CRSTOUR into @name
  end

  close CRSTOUR

  deallocate CRSTOUR

  update @Tab
  set   ROW = #TEMP.ROWS
  from  @Tab as G
         join #TEMP
           on G.TAB = #TEMP.NAME

  delete @Tab
  where ROW = 0

  open COURCHECK

  fetch NEXT from COURCHECK into @tabelle, @Spalte, @Typ

  while @@fetch_status = 0
  begin
    set @sql = N' if exists( select top 1 1 from dbo.'
               + @tabelle + ' where ' + @Spalte
               + ' is not null)
  begin
        if exists (select min(' + @Spalte
               + ') from dbo.' + @tabelle + ' having min('
               + @Spalte + ') <> max(' + @Spalte + '))
        begin
        set @Result = 1   
        end
        else
        begin
        set @result = 2
        end    
  end
  else
  begin
  set @result = 0
  end'

    set @params = N'@Result smallint OUTPUT @wert NVARCHAR(MAX) OUTPUT'

    exec SP_EXECUTESQL
      @sql,
      @params,
      @result = @vorhanden OUTPUT

    if @vorhanden = 1
    begin
      delete @Tab
      where TAB = @tabelle
         and SPALTE = @Spalte
    end

    if @vorhanden = 0
    begin
      set @debug = @debug + 1
    end

    /*    if @vorhanden = 0
        begin
          update @Tab
          set   ONLYNULL = 1
          where TAB = @tabelle
             and @Spalte = SPALTE
        end
       */
    if @vorhanden = 2
    begin
      set @sql = N' select top 1 @wert = cast(' + @Spalte
                 + ' as NVARCHAR(MAX) ) from dbo.' + @tabelle

      set @params = N'@wert NVARCHAR(MAX) OUTPUT'

      exec SP_EXECUTESQL
        @sql,
        @params,
        @wert = @einzigWert OUTPUT

      update @Tab
      set   WERT = @einzigWert
      where @tabelle = TAB
         and @Spalte = SPALTE
    end

    fetch NEXT from COURCHECK into @tabelle, @Spalte, @Typ
  end

  close COURCHECK

  select
    *
  from  @Tab

end


dank im vorraus

Dejan Vu 18. Apr 2014 07:29

AW: Spalten ohne Varianzen
 
Zitat:

Zitat von Mokus (Beitrag 1256032)
Hey hoy,

Hi girl.
Was erwartest Du? Du gehst durch alle Spalten aller Tabellen und führst für jede Spalte ein MAX und MIN aus, d.h. mindestens ein Indexscan, ansonsten ein Tablescan.

Verbesserung: Erstelle eine dynamische Query je Tabelle und werte die dann aus.

Code:
select min(field1) as f1min, max(field1) as f1max.... from Tabelle
Gewinn: Anstatt NxM queries (N=Tabellen, M=Spalten je Tabelle) nur N Queries.

Wofür das Ganze denn?

Zitat:

Fucking performance......
Muss das sein?

Mokus 22. Apr 2014 11:29

AW: Spalten ohne Varianzen
 
Hey.

Sinn, alle Spalten ausgeben die keine Varianzen haben.
Ich will ja nicht die Tabelle, sondern die Spalten Scan.

Das es lange dauern wird, war mir schon klar.
aber 16 stunden ....
Deshalb dachte ich ich könnte Tipps bekommen.


ich erwarte nicht, das es in 2 sek fertig ist.

und wie meins das für jede Tabelle erstellen ?
Jede Tabelle anschauen und dann ne SP schreiben ... ?


stellst du dir das mit der abfrage dann so vor:
Code:
select min(field1)as minfield1, max(field1), min(field2)as minfield2, max(field2), ... min(fieldN)as minfield N
having minfield1 <> maxfield1 or ... minfieldN <> maxfieldN
Problem, ich kann nicht genau bestimmen, welche Spalte nun gelöscht werden kann, da sie überall den gleichen wert hat-




MfG

ps.
Zitat:

Zitat:
Fucking performance......
Muss das sein?
wenn man schon im forum ein code postet, um zu hoffen eine vernüftige antwort zu bekommen, glaubst du nicht das ich verzweifelt bin ... ?
war zu diesen augenblick nicht ganz klar im Kop.
war falsch, sry.

Dejan Vu 22. Apr 2014 12:04

AW: Spalten ohne Varianzen
 
Zitat:

stellst du dir das mit der abfrage dann so vor:
fast, nur ohne 'HAVING'. Du bekommst eine Zeile und prüfst dann für jedes Feld, ob 'Min_Fieldx <>Max_Fieldx'. Wenn ja, hat die Spalte 'Fieldx' eine Varianz, so wie Du das nennst, bzw. unterschiedliche Werte.
Min_Field1Max_Field1Min_Field2Max_Field2
1233
Field1 hat unterschiedliche Werte, Field2 nicht.

Der Vorteil ist der, das pro Tabelle der Tablescan nur 1x durchgeführt wird (was er aber ohnehin muss). D.h. dieses Verfahren verkürzt deine Suche in etwa um den Faktor P, wobei P die durchschnittliche Anzahl von Spalten pro Tabelle ist. Natürlich würden einige Felder über einen Indexscan laufen, wenn man das separat pro Feld durchführt, aber länger dauert es in jedem Fall (außer, alle Felder sind indiziert).

Ich würde dein Script so umschreiben, das es einfach die o.g. dynamische Query pro Tabelle erzeugt, und das dann durchlaufen lassen. Die Prüfung, ob 'Min_Fieldx<>Max_Fieldx' kannst du immer noch machen. Du würdest dann aber sehen, ob und wieviel das bringt.

Ach, und sei mir nicht böse, aber auch 2014 ist es wünschenswert, vollständige deutsche Sätze mit korrekter Rechtschreibung und Grammatik zu posten. Das hat etwas mit Respekt vor demjenigen zu tun, der deinen Beitrag liest und dir helfen will: Stecke also mindestens die gleiche Sorgfalt in die Formulierung deines Beitrages wie Du erwartest (oder erhoffst), das der Antwortgeber es mit seiner Antwort tut. Wobei das ganz schön schwer ist, wenn man gerade wegen so einer Aufgabe angefressen ist. ;-)

Ich könnte nämlich auch einfach schreiben:
"Man, eine queri üba ale felda vonner tablele. No prob, bro."

PS: Schneller als das geht es imho nicht (oder Du legst über alle Spalten einen Index, am besten einen Column Store).

Mokus 23. Apr 2014 13:33

AW: Spalten ohne Varianzen
 
Ja, ich werde nun ein wenig auch auf miene Wort wahl achten ;)

mit dem Indexs hab ich mir auch durchüberlegt und auf einzelne Tabellen aufprobiert.
Dort dauert es zu lange zum anlegen und daraufhin wieder löschen ...


und mit den anderen, dass hat mir weiter geholfen, ich werde mal sehen ob das noch soviel bringt.


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:21 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz