Über den SQL-Server auf eine MySQL-Datenbank zugreifen.

Um mit Hilfe der Linked-Server Technologie auf eine MySQL-Datenbank zuzugreifen, müsste man folgendes tun:

Als erstes muß der Linked Server (auf deutschen Systemen ‘Verbindungsserver’ angelegt werden, dazu kann man folgenden Befehl verwenden:

sp_addlinkedserver
'myAlias'
, 'MySQL'
, 'MSDASQL'
, Null
, Null
, 'Driver={MySQL ODBC 3.51 Driver}; DB=myDatabase; UID=myUserName; PWD=myPassword; SERVER=localhost;'
go

EXEC sp_addlinkedsrvlogin
@rmtsrvname = 'myAlias',
@useself = 'TRUE',
@locallogin = NULL
go

Wichtig ist, das der ODBC-Treiber von MySQL auch auf der SQL-Server-Maschine installiert ist. Bei MySQL-Datenbanken, die auf anderen Rechnern betrieben werden, die als den localhost ist ein Benutzer einzurichten, der auch remote zugang auf die entsprechenden MySQL-Datenbanken hat.

Zugriff auf die entsprechenden Tabellen erhält man nach folgenden Schema:

Select * from openquery( linked Server Name,'PassThrougth Query')

Mit Hilfe von Openquery können auch Insert, Update und Delete Anweisungen ausgeführt werden, dazu sollte man aber Dokumentation lesen.

SQL-Server Reporting Services – Fehler 0x8007052E

Dieser Fehler tritt sehr häufig in größeren Umgebungen auf. Der SQL-Server Reporting Service nutzt bei der Verarbeitung eines Berichtes einen niedrig privilegierten Systembenutzer. Ist dieser User nicht „Local System“ kann es zu Problemen führen, wenn die Passwort-Richtlinien zu einer Veränderung des Passwortes zwingen. Spätestens nach dem Neustarten des SQL-Server Reporting Service ist es möglich das die Berichte nicht mehr richtig ausgeführt werden.

SQL-Server Reporting Services - Fehler 0×8007052E

Die Fehlermeldung: Anmeldung fehlgeschlagen: unbekannter Benutzername oder falsches Kennwort. Ausnahme von HRESULT: „0x8007052E“ kann aber ziemlich einfach behoben werden. Das Passwort für den „Execution Accout“ muss neu gesetzt werden.

Zur Erhöhung der Verfügbarkeit ist darauf zu achten, das die Sicherheitsrichtlinie für Passwort, das Passwort nicht automatisch verändert oder ungültig gemacht wird.

Recursive Queries – SQL-Server 2005

Heute habe ich wieder ein Highlight beim SQL-Server gefunden, was die Arbeit mit dieser Datenbank erheblich erleichtert. Ich hatte ein Problem und zwar mußte ich eine Hirachie und den entsprechenden Pfad aus der Datenbank ziehen.

Mein erster Gedanke war eine recursive Table-Valued-Funktion, die mir das Ergebnis zurückliefert. Das geht nun einfacher (leider erst im SQL-Server 2005):


declare @trenner nvarchar

set @trenner = '~';

WITH StructReports ( STRUKTURELEMENT_ID, VATER_STRUKTURELEMENT_ID, NAME , Level, path)
AS
(
-- Anchor member definition
SELECT
STRUKTURELEMENT_ID,
VATER_STRUKTURELEMENT_ID,
NAME ,
0 AS Level,
se.NAME as path
FROM dbo.Strukturelement as se
WHERE VATER_STRUKTURELEMENT_ID is null

UNION ALL

-- Recursive member definition

SELECT
se.STRUKTURELEMENT_ID,
se.VATER_STRUKTURELEMENT_ID,
se.NAME ,
Level +1,
sv.path + @trenner + se.Name as path
FROM dbo.Strukturelement as se
inner join StructReports as sv
on se.VATER_STRUKTURELEMENT_ID = sv.STRUKTURELEMENT_ID
)

Select * from StructReports r
order by path

Es ist zwar nicht eine so elegante Lösung, wie es Oracle mit dem Befehl “connect by” geschaft hat, aber es ist auch nicht schlecht.

Die hier gezeigt Möglichkeit gibt recursive die alle Elemente der Tabelle “Strukturelemente” zurück. Ein Struktur kann eine Verzeichnisstruktur oder eine Katalog sein, wie jeder mag. Hier hat sich Microsoft doch eine gute Methode einfallen lassen wie man endlich in der 9. Version des SQL-Servers Baumstrukturen per Select abrufen kann.

Best Practice für Log Files

Die Sicherung des Transaktionslogs ist eines der wichtigsten Dinge, die ein DBA einer Datenbank verstehen sollte. Den nur mit dem Transaktionslog können Datenbanken wieder bis zum Zeitpunkt des Crashs vollständig wiederhergestellt werden.

Zu diesem Thema habe ich unter http://www.insidesql.de/beitraege/administration/best_practice_fuer_log_files.html einen schönen Beitrag von Jonathan van Houtte gefunden, den ich hier nicht vorenthalten möchte.

Empfehlungen für Log Files für OLTP Datenbanken:

1: OLTP Produktionsdatenbanken sollten so gut wie nie die Datenbankoption “trunc. log on chkpt.” verwenden.

Die einzigen Vorteile dieser Einstellung sind:

  • daß man sich keine Gedanken über die Wartung (Backup) des Transaktionsprotokolls zu machen braucht
  • daß die “Gefahr”, kein Speicherplatz mehr zur Verfügung zu haben, weniger wahrscheinlich wird

Nachteile dieser Einstellung sind

  • Schlechtere Performance aufgrund des laufenden Truncate Prozesses
  • keine Point in time Wiederherstellungsmöglichkeit
  • keine Möglichkeit, den Zustand bis zum Zeitpunkt des Fehlers wiederherzustellen

Trifft man die Entscheidung, daß eine Wiederherstellung des letzten vollständigen oder differentiellen Backup’s ausreichend ist, dann gibt man Erfahrung zugunsten von Bequemlichkeit auf.

2: Wird das Transaktionsprotokoll nicht gesondert gesichert, kann es auch nicht verkleinert werden. Ein vollständiges oder differentielles Backup verkleinert nicht das Transaktionsprotokoll.

3: Transaktionsprotokoll Backup’s sind losgelöst von anderen Backup’s und können unabhängig davon wiederhergestellt werden. Angenommen, Sie führen ein vollständiges Backup jede Nacht durch und sichern das Transaktionsprotokoll zweimal im Laufe des Tages. Finden Sie jetzt heraus, daß das letzte nächtliche Backup korrupt ist, können Sie das aus der Nacht zuvor wiederherstellen (WITH NORECOVERY!) und anschliessend die Log Backup’s wiederherstellen, um einen möglichst aktuellen Stand zu erreichen.

4: Das erste, was Sie in einem Disaster Fall machen sollten, ist, versuchen das Transaktionsprotokoll zu sichern. DBA’s, die ich unterrichte, werden darauf gedrillt.

5: Verwenden Sie SQL Server 7 und setzen die Einstellung “select into/bulkcopy” auf Wahr, um beispielsweise Daten aus einer Textdatei schnell zu laden, sollten Sie direkt danach die Einstellung wieder auf Falsch setzen, das Transaktionsprotokoll und dann die Datenbank sichern. SQL Server 2000 and höher können die Änderungen mit ihrem Bulk-Logged Recovery Model wiederherstellen. Allerdings nicht auf der einzelnen Vorgangsebene. Die Verwendung dieses Modells und Durchführung einer Bulk-Logged Operation verhindert Point in time Wiederherstellung (mit der dafür notwendigen Transaktionsprotokollsicherung) und limitiert Ihre Möglichkeiten, auf eine Korrumpierung Ihrer Datenbankdateien zu reagieren. Speichern Sie in der Datenbank unternehmenskritische dynamische Daten, sollten Sie sich genau überlegen, ob Sie die Fehlertoleranz des Full Recovery Models aufgeben zugunsten der Performance des Bulk-Logged Modells. Bedenken Sie dabei auch, daß auch SELECT INTO, CREATE INDEX, WRITETEXT und UPDATETEXT minimal protokollierte Operationen sind, genauso wie die offensichtlicheren BULK COPY und bcp.

6: Führen Sie die Transaktionsprotokollsicherung vor einem vollständigen oder differentiellen Backup durch statt danach. Sichern Sie das Transaktionsprotokoll nach der Datenbank, müssen Sie dieses Log Backup zusätzlich wiederherstellen, wenn Sie das Datenbankbackup wiederherstellen.

7: Verkleinern Sie nicht das Transaktionsprotokoll nur um des Verkleinerns willen. Die Protokolldateien sollten so dimensioniert sein, daß sie die maximale Menge an protokollierten Informationen zwischen zwei Backup Vorgängen aufnehmen können. Bestehen Sie auf der Verkleinerung, werden die Dateien vergrößert, wenn dies notwendig ist. Dies wiederum geht auf die Performance des Gesamtsystems, da Prozessorleistung für den Autogrow Vorgang benötigt wird und führt ferner zu Dateifragmentierung. (Gleiches gilt übrigens auch für Datendateien. Erwarten Sie, daß die Datenbank auf eine Größe von 20 GB anwachsen wird, sollten Sie auch diesen Speicherplatz direkt bei Erstellung der Datenbank allokieren).

8: Vergewissern Sie sich, daß Sie in einem Disasterfall in der Lage sind, eine Datenbank auf den aktuellsten Stand wiederherzustellen. Erstellen Sie eine Testdatenbank und warten diese exakt so, wie Ihre Produktionsdatenbanken. Führen Sie dann eine Notfallübung durch, indem Sie simulieren, daß die Hardware mit den Datendateien mit einem Fehler ausfällt. (Was ist das Erste, was Sie in einem solchen Fall machen? Punkt 4!). Überprüfen Sie Ihre Bandsicherungen und Wiederherstellungpläne wenigstens vierteljährlich, bzw, immer dann, wenn sich etwas in Ihrem Backup Prozess verändert. Sie können sich nur dann sicher sein, daß Ihre Backup funktionieren, wenn Sie sie ausprobieren und weiderherstellen; und sicherlich wollen Sie das nicht erst auf die harte Tour herausfinden. Üben Sie ebenso die Point in time Wiederherstellung. Ich bin dafür bekannt, die WHERE Klausel im DELETE Statement anzugeben.

9: Festplatten und andere Hardware werden irgendwann ausfallen. Die Frage ist nicht, ob, sondern, wann.

10: Sichern Sie die Datenbankdateien (mdf, ndf und ldf) erst dann, wenn Sie vorher die Datenbank mit sp_detach offline genommen haben oder den SQL Server Dienst gestoppt haben. Diese “Backup’s” sind nicht verwendbar mit differentiellen oder Transaktionsprotokollbackup’s. Auch wenn Sie später SQL Server verwenden, um sie zu sichern und mit No RECOVERY wiederherzustellen. Müssen Sie ein Backup Utility ohne nativen SQL Server Support verwenden, verwenden Sie SQL Server, um die Datenbanken und Transaktionsprotokolle auf Festplatte zu sichern (aber bitte auf einer separaten physikalischen Platte!) und verwenden anschließend Ihr Backup Utility, um diese Backup Dateien zu sichern. Sichern Sie auf einen anderen Server, beachten Sie bitte, daß der Service Account mit dem SQL Server oder der SQL Server Agent gestartet wird, ein Domänen User sein muß, der auch auf dem Remote Server angelegt sein muß. Zusätzlich sollte ein RESTORE VERFIYONLY angewendet werden, wenn auf einen Remote Server gesichert wird.

11: Löschen oder überschreiben Sie kein Backup, solange Sie nicht wenigstens zwei voneinander unabhängige Wiederherstellungsalternativen haben (siehe Punkt 3:).

12: Logging läßt sich nicht abschalten. Es ist ein integraler Bestandteil von SQL Server und garantiert die ACID Eigenschaften des Systems.

13: Verwenden Sie einen Write-Cache Disk Controller, stellen Sie sicher, daß sein Speicher redundant ist und batteriebetrieben. Lernen Sie, wie man seinen Speicher im Falle eines Disasters wiederherstellt. Deaktivieren Sie Caching auf den Platten selbst.

14: Stellen Sie sicher, daß die Transaktionsprotokolle auf redundanten physikalischen Platten sind und nicht auf dem gleichen Array wie die Daten. RAID 1 ist ideal für Transaktionsprotokolle, da ihr typischer I/O (im Gegensatz zu den Datendateien) sequentiell ist. Haben Sie mehrere Datenbanken gleichzeitig in Benutzung, kann es sinnvoll sein, jedes Transaktionsprotokoll auf einem eigenen RAID1 Platten Paar zu haben; anderenfalls könnte auf dem sequentiellen I/O ein random I/O werden.

Ich wollte einfach nur dividieren

Ja, gestern wollte ich einfach nur dividieren. Einen Dividenden durch einen Divisor, das ergibt ja einen Quotienten … 🙂

Klingt ganz einfach … denkste … auf dem SQL-Server ist es das nicht, wie ich spüren musste. Eigentlich wollte ich eine ganz einfache Rechnung durchführen. In einer Tabelle A gibt es zwei Integerspalten X und Y diese beiden Spalten sollten gegeneinander verrechnet werden.

Folgendes SQL-Stament habe ich verwendet:

select X/Y as Quotient from A

die ersten Tests sahen auch vielversprechend aus.

Hier eine kleine Übersicht:

4 / 2 = 2
64 / 4 = 16

Beim weiteren Test ergab sich folgende Situation:

50 / 4 = 12
5 / 3 = 1

Das machte mich dann doch etwas stutzig, da ich das vom SQL-Server nicht gewohnt war. Ein Blick in die Dokumentation bestätigt, der SQL-Server macht eine Integerdivision.

Ich hätte nie gedacht, dass der SQL-Server eine Integer-Division durchführt, nach dem gesunden Menschenverstand erwartet man, das hier eine Gleitkommazahl herauskommt.

Hier verhält sich der SQL-Server nicht so wie es andere Datenbanken tun. Oracle, Access und MySQL tun dies richtig. Das ist sehr ärgerlich, denn jetzt muss ich bei einer normalen Division noch eine Typenbetrachtung durchführen.

Ist zwar einfach, aber ärgerlich, das Statment würde jetzt zum Beispiel so aussehen:

select X/cast(Y as float) as Quotient from A

Dann gibst das richte Ergebnis:

50 / 4 = 12,5
5 / 3 = 1,6667

Ich frage mich nur, muss das sein … Microsoft macht es den Entwicklern wieder besonders schwer. Einen Entwickler kann man das ja noch zutrauen, aber viele meiner Kunden, verwenden den SQL-Server für Abfragen. Ob denen das Problem so bewusst ist? Ich werde sie darauf hinweisen, aber was ist mit dem Rest der Welt ….

Die Gründe von Microsoft werde ich wahrscheinlich nie verstehen … wie so manches anderes

%-Zeichen in Like Bedingung berücksichtigen

Man lernt ja nie aus, nach jahrelanger SQL-Erfahrung stand ich nun vor dem Problem aus einer Textspalte einer SQL-Server-Datenbank alle Werte mit einem ‘%’-Zeichen zu extrahieren. Einfacher gesagt als getan, den das ‘%’-Zeichen ist ein Platzhalter für beliebige Zeichen. Da mußte ich also doch Dokumentation wälzen und habe dann den Befehl gefunden, der hilfreich ist.

Man erweitert den LIKE Operator um den die Answeisung ESCAPE, dann klappt es.

match_expression [NOT] LIKE pattern [ESCAPE escape_character]

Im Beispiel sieht das so aus:

SELECT foo FROM batz WHERE txt LIKE '% 19!%' ESCAPE '!'

Hier ist das !-Zeichen das Escapezeichen für Prozent. Das tolle dabei ist, das der Escapecharakter seperat definiert werden kann, den man weis ja nie wie eine Bedingung aussehen kann und der SQL-Server kann nicht raten.

Das tolle bei dem SQL-Befehl ist, das er auch bei Oracle-Datenbanken funktioniert, und kann so in datenbankunabhänigigen Prgrammen verwendet werden.

Transaktionssichere Stored Procedure im SQL-Server 2005

Heute hatte ich wieder ein interessantes Problem im SQL-Server 2005. Ich musste eine Prozedure schreiben die Transactionssicher war, das heißt die Veränderungen im Fehlerfalle richtig zurücknimmt, aber auch ein Rollback durch äußere Transaktionen zuläßt.

Hier die Lösung die ich gefunden habe:


CREATE PROCEDURE [dbo].[UpdateOrInsertValue]

@Key int, --Primary Key
@Value money = 0 --Value

AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;

DECLARE @TranCounter INT;
SET @TranCounter = @@TRANCOUNT;
IF @TranCounter > 0
SAVE TRANSACTION VerteilungNachMonatenSpeichern;
ELSE
-- Procedure must start its own
-- transaction.
BEGIN TRANSACTION;

BEGIN TRY

-- Monat 1
UPDATE table1 SET Wert = @Value WHERE (ID = @Key)
if @@ROWCOUNT <1 Insert into Table1 (ID, Wert) values (@Key, @Value) IF @TranCounter = 0 COMMIT TRANSACTION; END TRY BEGIN CATCH IF @TranCounter = 0 -- Transaction started in procedure. -- Roll back complete transaction. ROLLBACK TRANSACTION; ELSE -- Transaction started before procedure -- called, do not roll back modifications -- made before the procedure was called. IF XACT_STATE() <> -1
-- If the transaction is still valid, just
-- roll back to the savepoint set at the
-- start of the stored procedure.
ROLLBACK TRANSACTION VerteilungNachMonatenSpeichern;
-- If the transaction is uncommitable, a
-- rollback to the savepoint is not allowed
-- because the savepoint rollback writes to
-- the log. Just return to the caller, which
-- should roll back the outer transaction.

-- After the appropriate rollback, echo error
-- information to the caller.
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;

SELECT @ErrorMessage = ERROR_MESSAGE();
SELECT @ErrorSeverity = ERROR_SEVERITY();
SELECT @ErrorState = ERROR_STATE();

RAISERROR (@ErrorMessage, -- Message text.
@ErrorSeverity, -- Severity.
@ErrorState -- State.
);
END CATCH

END
GO