Glorf.it

Glorf IT

Bedenkliches aus dem IT-Alltag

11. Oktober 2007 um 22:00

Unstrukturierte Daten

"Damals, zu einer Zeit in der Lügen noch geholfen hat…" (so beginnen bei Kpt. Blaubär die Märchen, die er seinen Neffen erzählt) sollte es einmal ein neues Dateisystem geben, dass vollständig in den SQL-Server integriert war: WinFS sollte das Baby heißen. Aber es zeigte sich, dass das Kind nicht gewollt war und deswegen wurde das Projekt begraben. Die Entwickler der aufgelösten Arbeitsgruppe beteuerten, dass deren Erkenntnisse in den SQL-Server eingehen würden, aber niemand glaubte Ihnen. Im SQL-Server-2005 war tatsächlich nicht ein Hauch davon zu erkennen. Das wunderte indes niemanden…

Aber was hören wir da vom SQL-Server-2008? Sollten wir uns alle getäuscht haben? Das neue Kern-Feature heißt: "Filestream"

The proliferation of digital content has significant implications for the way in which organizations store and access business data. Increasingly, databases that are at the core of business applications must be integrated with unstructured data in the form of documents, images, video content, and other multimedia formats. Organizations increasingly need to be able to store and manage digital data of all formats in order to manage the information lifecycle, meet compliance requirements, and implement content management solutions.

Hier stehen mehr Infos dazu: "Managing Unstructured Data with SQL Server 2008"

9. Oktober 2007 um 18:34

Astoria CTP

Als ich heute im ".Net Briefing" las, dass man jetzt der neue Astoria September CTP verfügbar sei, musste ich erst mal nachlesen was das überhaupt ist. Der CTP kam sogar schon vor 3 Wochen raus und ging mir irgendwie durch die Lappen…

Auf der Microsoft-Seite zum Project Codename "Astoria" wird es erklärt:

The goal of Microsoft Codename Astoria is to enable applications to expose data as a data service that can be consumed by web clients within a corporate network and across the internet. The data service is reachable over HTTP, and URIs are used to identify the various pieces of information available through the service. Interactions with the data service happens in terms of HTTP verbs such as GET, POST, PUT and DELETE, and the data exchanged in those interactions is represented in simple formats such as XML and JSON.

Irgendwie wird das ganze Gebiet rund um den SQL-Server immer größer und sumpfiger. Diejenigen, die da noch den Überblick haben, bewundere ich… 😉

2. Oktober 2007 um 21:21

XML im SQL Server 2008

Weil ich demnächst wieder eine Feierabend-Schulung zum Thema XML im SQL-Server halte, habe ich mir die neuen XML-Features im SQL-Server-2008 mal angelesen. Wie es aussieht, ist kein großer Wurf dabei, eher Detailpflege und Verbesserungen bestehender Features. Der große Wurf an dieser Stelle kam eindeutig mit dem SQL-Server-2005. Das kommt mir sehr gelegen, weil ich mit dem SQL-Server-2008 noch weiter nichts gemacht habe… 😉

  • Erweiterungen rund um das Schema und neue Deklarationsmöglichkeiten, z.B. eine "laxe" Validierung und den List-Typ
  • XQuery-Erweiterungen, wie z.B. "let" für Variablen. Bisher fehlte das "L" in "FLOWR". Das war nicht schön, aber ging auch.
  • im XML-Insert können jetzt Variablen benutzt werden.

Wen das Thema interessiert, der findet Details im Dokument "What's New for XML in SQL Server 2008".

25. September 2007 um 19:29

gesperrte Resource identifizieren

Für alle, die letzten Dienstag auf dem PASS-Treffen in Nürnberg waren: Wir rätselten, wie man für eine Sperre feststellen kann, welche Ressource betroffen ist. Es geht hier um die Info, die z.B. mit sp_lock angezeigt wird.

Ich fand dazu doch keine Info im SQL-Server-Magazine. Aber das ist recht gut und ausführlich in den Books-Online bei "sys-dm_tran_locks" beschrieben. Wenn man die View abruft, dann kann man anhand der Datenbank–ID und der Ressource-ID (steht in "resource_description") feststellen, welches Objekt genau gesperrt wurde. Dazu benötigt man noch die Datenbank-ID (siehe unten) und ggf. die ID der übergeordneten Ressource (resource_associated_entity_id ), die enthält z.B. meist die "heap or b-tree ID" falls eine Seite gesperrt wurde.
Wegen der vielfältigen Möglichkeiten ist es nicht ganz unaufwändig dafür eine allgemeine Interpretationsfunktion zu schreiben.

Dabei muss man beachten, dass die Objekt-IDs jeweils auf eine Datenbank bezogen sind. Aber das kann man mit einem neuen Feature des SQL-Servers-2005 lösen. Während man früher für die Funktion "object_name()" immer sicherstellen musste, dass man in der richtigen DB war, kann man heutzutage die relevante Datenbank angeben.

Bisher (geht immer noch):

use northwind
select object_name(21575115);
–> Orders
go
use Adventureworks
select object_name(21575115);
–> uspLogError

Jetzt möglich:
use master
select object_name(21575115, db_id('Northwind'));
–> Orders

Damit kann man eine Auswertung schreiben, die neben der internen Angabe der Sperren auch das Objekt im Klartext nennt: Fleißige vor…

21. September 2007 um 18:39

SQL-Server: Sessions und Connections

Im SQL-Server-2005 wird zwischen Sessions und Connections unterschieden. Als ich das in dieser Woche bemerkte, musste ich ziemlich lange suchen bis ich den Unterschied bzw. die Zusammenhänge verstand:

Eine Session in SQL-Server-2005 ist das, was "früher" der System-Prozess war, den man in der Systemtabelle "sysprocesses" beobachten konnte. Jede Session hat eine Session-ID, die exakt dem entspricht, was bisher die SPID (system process ID) war. Neben den Session, die von Benutzern kommen, gibt es auch eine ganze Reihe von Sessions, die vom SQL-Server zur internen Verwaltung genutzt werden ("internal tasks"). Wie bisher sind sie daran erkennbar, dass deren Session-ID kleiner als 50 ist.
Informationen über Sessions kann man aus der Dynamic-Management-View (DMV) sys.dm_exec_sessions erfahren. Darin stehen neben den "bisherigen" Infos auch jede Menge Eigenschaften der Session, z.B. die aktuell gesetzten Werte der einschlägigen Settings, z.B. den Isolation-Level oder den Lock-Timeout. Sehr praktisch!

Jede Verbindung, die von "außen" zum SQL-Server aufgebaut wird, ist eine "Connection". Jeder Connection ist genau eine Session zugeordnet. Ich habe lange rumgerätselt, ob eine Session auch mehrere Connections haben kann, das ist zwar laut Doku möglich, ich fand aber keinen Hinweis darauf in welchen Fällen das wie gehen soll. Aber es scheint so zu sein, dass eine Connection nacheinander mehrere Sessions haben kann. Das scheint bei SOAP-Verbindungen relevant zu sein.
Connection-Informationen stehen in der DMV sys.dm_exec_connections. Hier finden sich dann auch die Netzadresse des Clients, das Login und solche Dinge. Schick ist, dass es pro Connection eine eindeutige unique ID gibt. Damit hat man endlich eine brauchbare ID, die nicht nach Beenden der Connection sofort wieder verwendet wird, wie das bei der SPID ist.

Daneben gibt es übrigens auch noch den Request. Jede Session kann mehrere Request ausführen. Darin wird das auszuführende SQL-Statement hinterlegt, die Transaktion, der Zugriffsplan usw.
Diese Infos stehen unter sys.dm_exec_requests. Neben den oben genannten Dingen stehen hier auch Status, Blockierungsinformationen und I/O-Informationen.

Für weitere Infos zu dem Thema empfehle ich den Artikel "Dynamic Management Views" auf SQLTeam.com.

14. September 2007 um 19:27

SQL-Server: select * in Views

Wenn man "select *" verwendet, dann erwartet man immer alle Attribute einer Tabelle in der Ergebnismenge. Das ist für AdHoc-Abbfragen sehr praktisch, aber für den Einsatz in Programmen ungeeignet.

  • Wenn man später die Tabelle um eine weitere Spalte ergänzt, dann leifert der Befehl plötzlich eine um das Feld erweiterte Ergebnismenge, mit der die Anwendung nicht rechnet.
  • Außerdem erwartet meine Anwendung die Spalten in einer bestimmten Reihenfolge. Nach einer Datenbankänderung kann sich die Reihenfolge aber ändern.

In beiden Fällen muss ich meine Anwendung ändern und das ist sicher mehr Aufwand als die Spalten auszuformulieren, zumal das Visual-Studio for DB-Pros jetzt auch im Refactoring das "*" durch die aktuellen Spalten ersetzen kann.

In Views führt ein "select *" zu einem "eigenwilligen" Verhalten. Es werden hier nämlich nicht immer alle Attribute einer Tabelle in der Ergebnismenge angezeigt!

  • Wenn eine neue Spalte in einer Basistabelle hinzukommt, dann ändert sich die View-Definition bzw. die Struktur seiner Ergebnismenge dadurch nicht. Es werden danach weiterhin nur die "alten" Attribute angezeigt.
  • Wenn eine vorhandene Spalte geändert wird, dann ändert sich die View nicht, es werden die gleichen Spalten (inkl. Typen) zurückgeliefert, wie vor der Änderung. Die Werte werden jedoch aus dem neuen in den alten Datentyp konvertiert.
  • Wird eine vorhandene Spalte entfernt und die View enthält nun mehr Spalten als die Tabelle, dann kommt eine Fehlermeldung.
  • Wird hingegen eine neue Spalte angefügt und eine vorhandene Spalte entfernt, dann wird die View nicht compiliert und die Werte werden aus den falschen Spalten angezeigt. Die Neue wird hinten angefügt und die Fehlende einfach weggelassen.

Blöderweise wird darauf in den Books-Online nicht explizit hingewiesen. Stattdessen wird in allen Beispielen bei "CREATE VIEW" das "*" verwendet! Bei MS liest sich das so:

If a view is not created with the SCHEMABINDING clause, sp_refreshview should be run when changes are made to the objects underlying the view that affect the definition of the view. Otherwise, the view might produce unexpected results when it is queried.

Hier ein paar Samples, zum selber ausprobieren:

use tempdb
go

– Aufräumen, wenn nötig
if object_id('blabla') IS NOT NULL drop table blabla
if object_id('vlavla') IS NOT NULL drop view vlavla
go
– Testtabelle anlegen
create table blabla (id integer identity(1,1), bla varchar(200), z integer)
go
– und füllen
insert into blabla (bla, z) values ('2007-31-12 12:12', 1)
insert into blabla (bla, z) values ('2007-31-12 12:12', 2)
insert into blabla (bla, z) values ('2007-31-12 12:12', 3)
insert into blabla (bla, z) values ('2007-31-12 12:12', 4)
insert into blabla (bla, z) values ('2007-31-12 12:12', 5)
go
– View anlegen
create view vlavla
as select * from blabla
go
– So sieht das Ergebnis im Original aus
select * from vlavla
go

– Tabelle ändern: neue Spalte hinzu
ALTER TABLE blabla ADD muh datetime null
go
UPDATE blabla SET muh = getdate()
go
select * from vlavla
go

– Tabelle ändern: Datentyp ändern
ALTER TABLE blabla ALTER COLUMN bla datetime
go
select * from vlavla
go

– Tabelle ändern: Spalte entfernen (Aber es sind noch so viele Spalten in der Tabelle, wie in der View-Definition)
ALTER TABLE blabla DROP COLUMN bla
go
– So sieht in der View aus
select * from vlavla
– Und so die echte Tabelle
select * from blabla
go

– Tabelle ändern: noch eine Spalte entfernen (Nun sind weniger Spalten in der Tabelle als in der bisherigen View-Definition)
ALTER TABLE blabla DROP COLUMN muh
go
select * from vlavla
–> Jetzt kommt ein Fehler!

12. September 2007 um 23:24

Paul Randal ist nicht mehr bei Microsoft

OK, wahrscheinlich wissen es sowieso schon alle, aber ich habe mich immer noch nicht durch alle Blogs-Postings meiner 4 Urlaubswochen durchgeackert: Paul Randal ("Mr DBCC") ist nicht mehr bei Microsoft. Wie schade. Er sucht sein Auskommen jetzt bei SQLskills mit Schulungen, in denen er sein bei MS erworbenes Wissen weiter gibt. Naja, wenigstens erhöht das die Chancen ihn auch mal auf ein paar europäischen Konferenzen zu sehen…

In dem Zuge hat er auch ein neues Weblog begonnen: "In Recovery…". Sein erster Artikel ist eine aktualisierte Zusammenfassung von Artikeln seines alten Weblogs über defekte Datenbanken. Lesenswert.

5. September 2007 um 18:01

Zugang zum SQL-Server erzwingen

Ende Juli veröffentlichte Microsoft eine Beschreibung, wie man sich mit ansonsten abgeschotteten SQL-Servern verbinden kann. Voraussetzung dazu ist, dass man den Dienst stoppen/starten kann. Dazu muss man lediglich den Startparameter "-m" anfügen.

Das kann man natürlich wie beschrieben über die Registry machen, aber das ist ja nicht wirklich spaßig. Ich würde das Werkzeug SQL Server Configuration Manager"" (Aufruf über "Startmenü\Alle Programme\Microsoft SQL Server 2005\Configuration Tools\SQL Server Configuration Manager" oder mittels Start\Ausführen "SQLServerManager.msc"): Dort unter Eigenschaften des SQL-Server-Dienstes im Reiter "Advanced" im Eintrag "Startup Parameters" unten noch "-m" hinzufügen. Dann den Dienst einfach neu starten.

Man kann das auch gerne direkt unter "Start\Ausführen" machen:
"c:\Programme\Microsoft SQL Server\MSSQL.1\MSSQL\Binn\sqlservr.exe" -sMyYukon -m -c

Jetzt kann man sich ganz einfach mittels der Windows-Authentifizierung zu dem SQL-Server verbinden und das vergessene SA-Passwort zurücksetzen oder andere schöne Dinge tun. Denn man hat nun Adminrechte. Am Ende darf an nicht vergessen den Parameter "-m" wieder zu entfernen, sonst hat man den ansonsten lästigen Single-User-Mode immer…

Wenigstens gibt es eine Einschränkung: Für diese Methode benötigt man Admin-Rechte an den betreffenden Rechner. Offensichtlich geht Microsoft davon aus, dass der Windows-Admin auch Administrator des SQL-Servers ist.

Weitere Details stehen im KB-Artikel 937682 "How to add a Windows user to the sysadmin fixed server role in SQL Server 2005 as a failure recovery mechanism"

Vielen Dank an Spencer Tracy, der das sogar schon am Tag vor meinem Urlaub als Kommentar postete.

29. August 2007 um 12:35

SQL-Server-Hotfixes per WSUS installieren

Weil ich in einem anderen Blog gerade einen Beitrag zum Windows Server Update Services (WSUS) sah, fiel mir ein neues Feature ein, dass ich mit sehr gemischten Gefühlen sehe:

Man kann jetzt sicherheitskritische Hotfixes zum SQL-Server-2005 automatisch per WSUS installieren lassen. Dazu muss man dem WSUS lediglich sagen, dass er auch die SQL-Server-Hotfixes runterladen soll und auf welchen PCs er sie installieren soll.

Das ist von der Idee her ganz praktisch, aber hat doch ein paar "Herausforderungen":

  • Man kann nicht einzelne Instanzen angeben oder ausschließen. Das kleinste Korn ist der Rechner.
  • Der Update-Client muss in einem Benutzerkontext laufen, der Adminrechte hat. Andernfalls wird der Hotfix-Update gestartet, kopiert schon mal fleißig los, kann sich nicht zum SQL-Server verbinden und beendet daraufhin den SQL-Server-Dienst. Der Stand ist danach völlig inkonsistent. MS hat es abgelehnt das als Bug anzuerkennen.
  • Zukünftig (zuerst nur für SQl-Server-2008) werde ein Feature genutzt mit dem sie auch dann Hotfixes installieren können, wenn der Dienste-Benutzer keinen Zugriff zum SQL-Server hat.
  • Man weiß nicht, welche Hotfixes installiert werden sollen. Neulich wurde ein Hotfix ausgeliefert, der nicht sicherheitsrelevant war. In dem Security-Bulletin war er auch nciht erwähnt. Trotzdem wurde er installiert. Die Antwort von MS darauf war, dass es ein kritischer Hotfix sei und er deswegen ausgeliefert wurde. Woran man das erkennen könne? Na daran, dass er vom WSUS ausgeliefert wurde. Nein, das wird nicht dokumentiert.

Wenn man bedenkt, dass Gordon Mangione damals noch davon abriet einfach SP1 für den SQL-Server-2000 zu installieren. Man solle das erst mal auf einem Testrechner installieren, gründlich die Nebenwirkungen auschecken und dann geplant umsteigen. Dabei werden SPs sehr gründlich getestet, jedenfalls im Vergleich zu den Hotfixes. Und jetzt soll das ratzfatz am Server installiert werden? Wen fragt man zu Risiken und Nebenwirkungen der Hotfixes?

21. August 2007 um 12:10

fieser Fehler im Tablediff

Neulich stellte ich das Tool TableDiff des SQL-Servers-2005 vor. Leider hat es einen ganz fiesen Fehler:

Lässt man das Werkzeug TableDiff ein Fix-File ("-f") erzeugen, also ein Skript mit den INSERT/UPDATE/DELETE-Befehlen, die Datenbank 2 auf den Stand der ersten heben, dann können dabei fehlerhafte SQL-Befehle erzeugt werden. Die Werte vom Typ NUMERIC liefern falsche Ergebnisse, wenn das Tool von einem Benutzer mit deutschen Ländereinstellungen ausgeführt wird. Als Dezimalpunkt wird dann "," anstelle von "." verwendet, was in SQL natürlich syntaktisch falsch ist.

Anstelle von (numerischer Wert: 12.34)
INSERT INTO [dbo].[difftest] ([id],[num]) VALUES (1,12.34)
kommt leider (numerischer Wert: 12,34)
INSERT INTO [dbo].[difftest] ([id],[num]) VALUES (1, 12,34)

Microsoft erkannte den Bug recht schnell an. Der Entwickler hatte bei der Ausgabe einfach nur ToString() angegeben ohne daran zu denken, dass die Konvertierungsfunktion von den Ländereinstellungen abhängt. Er hätte einfach eine feste Ländereinstellung vorsehen sollen.

Microsoft hat einen Bugfix dazu abgelehnt. Jeder der das Tool in Europa einsetzen will, der muss sich etwas überlegen. Wer einfach seine Ländereinstellungen ändern kann, ist fein raus. Bei mir geht das nicht.
Ich werde mir so behelfen:

  • Ich legte einen lokalen Benutzer "englisch" an. Einmal musste ich mich anmelden und die Ländereinstellungen auf us-amerikanisch setzen.
  • Jetzt starte ich meine Dos-Box immer unter dem Benutzer. Wenn ich dann das Tablediff aufrufe, sind die Befehle richtig.
  • Dazu nutze ich eine kleine selbstgeschriebene RunAs-Variante, der man gleich ein Passwort mitgeben kann. So kann ich eine Verknüpfung hinterlegen, die die Dos-Box sofort (ohne lästigen Dialog) startet.

Das ist natürlich nur eine Notlösung, aber was soll man machen…

18. August 2007 um 10:25

SQL-Server-Konfigurationsparameter

Mit der Abfrage

select name, is_dynamic, is_advanced, minimum, maximum, value, value_in_use, description
from sys.configurations

bekommt man übrigens die Liste der Konfigurationseinstellungen des SQL-Servers-2005. Interessant ist, dass man hier genau sehen kann, ob ein Parameter dynamisch ist oder nach der Änderung ein Neustart des Dienstes erforderlich ist.

"Value_in_use" ist der aktuell gültige Wert, "Value" ist der Wert, der zuletzt mit sp_configure eingestellt wurde.

13. August 2007 um 12:38

SQL-Server undokumentiert: DBCC PAGE

Als ich die Systemdatenbank mssqlsystemresource neulich mal untersucht, versucht ich mein Glück zunächst mit einem nur halb dokumentierten DBCC-Befehl: ersteht nicht in den Books-Online, aber in der Knowledgebase steht dann doch eine Anleitung.

Der Aufruf ist recht schlicht und kann aus einer beliebigen Datenbank erfolgen:

DBCC PAGE( {dbid|dbname}, filenum, pagenum [, printopt] [, cache] [,logical] )

Damit der Output sichtbar ist, muss man dem SQL-Server vorher noch sagen, dass er an den Client geschickt werden soll und nicht etwa ins Errorlog:

DBCC TRACEON (3604)
DBCC PAGE (32767, 1, 1, 1)

Parameter Beschreibung
dbid ID der Datenbank
dbname Datenbankname
filenum Dateinummer (1 ist immer die MDF, 2 meist die LDF, usw.)
pagenum Seitennummer in der Datei
printopt optional:
0: Default; Buffer- und Page-Header
1: Buffer- und Page-Header; jeden Datensatz einzeln und die Satz-Offset-Tabelle
2: wie 1, aber alle Datensätze zusammen
3: wie 1, aber die Daten im Klartext
cache optional:
0: lädt die Seite "frisch" aus der Datenbank-Datei
1: zeigt die Seite aus dem Cache (Default)

Ich habe das zum Glück noch nicht oft benötigt, aber irgendwie finde ich es echt cool mir die Datenseiten so richtig ansehen zu können…

Siehe auch