Skip to content

Converting IMAGE to VARBINARY(max) on SQL Server

With Microsoft SQL Server 2005 the IMAGE and (N)TEXT large data types have been deprecated in favor of VARBINARY(MAX) and (N)VARCHAR(max). We have some older database schema at customers who still use the IMAGE type so I am preparing a note to guide the migration.

There is an easy ALTER TABLE command to convert the existing tables, however it is not clear what the impact of this conversion is. So I took a deeper look. I noticed that converting a VARBINARY(max) back to IMAGE caused a lot of I/O and log usage. The other way around this seems to not happen and I can not repeat the problem.

Nevertheless I tried a few scenarios with type and parameter conversion. With IMAGE the default is to not inline data and it is configured with the 'text in row' table option which allows to define a limit of data which is inlined.

The following statement creates 4 tables with different settings for images, two heap tables and two clustered:

DROP TABLE tableHeapWithImageDefault;
DROP TABLE tableHeapWithImageInline;
DROP TABLE tableClusteredWithImageDefault;
DROP TABLE tableClusteredWithImageInline;

CREATE TABLE tableHeapWithImageDefault (cID INT identity(1,1) PRIMARY KEY NOT NULL, cImage IMAGE);
CREATE TABLE tableClusteredWithImageDefault (cID INT identity(1,1) PRIMARY KEY CLUSTERED NOT NULL, cImage IMAGE);

CREATE TABLE tableHeapWithImageInline (cID INT identity(1,1) PRIMARY KEY NOT NULL, cImage IMAGE);
EXEC sp_tableoption 'tableHeapWithImageInline', 'text in row', 'ON';

CREATE TABLE tableClusteredWithImageInline (cID INT identity(1,1) PRIMARY KEY CLUSTERED NOT NULL, cImage IMAGE);
EXEC sp_tableoption 'tableClusteredWithImageInline', 'text in row', 'ON';

If I query the details I see the following:

select name, type_desc, lob_data_space_id, text_in_row_limit, large_value_types_out_of_row from sys.tables where name like 'table%'

name                             type_desc     text_in_row_limit large_value_types_out_of_row
tableClusteredWithImageDefault   USER_TABLE    0                 0
tableClusteredWithImageInline    USER_TABLE    256               0
tableHeapWithImageDefault        USER_TABLE    0                 0
tableHeapWithImageInline         USER_TABLE    256               0

The large_value_type_out_of_row cannot be modified as long as the table does not contain a new large type.

So lets fill the tables with smaller and larger values (total blob size of (36000+180)*50000=1.6GB) for the cImage column and see what space usage the allocation units have:

while @x < 10 BEGIN
  set @x = @x + 1
  select @x
  BEGIN TRANSACTION
  declare @i int = 0;
  while @i < 5000 BEGIN
    INSERT INTO tableHeapWithImageDefault(cImage) VALUES(replicate(cast(newID() as VARCHAR(max)),5)) -- 180
    INSERT INTO tableHeapWithImageDefault(cImage) VALUES(replicate(cast(newID() as VARCHAR(max)),1000)) -- 36000
    INSERT INTO tableHeapWithImageInline(cImage) VALUES(replicate(cast(newID() as VARCHAR(max)),5))
    INSERT INTO tableHeapWithImageInline(cImage) VALUES(replicate(cast(newID() as VARCHAR(max)),1000))
    INSERT INTO tableClusteredWithImageDefault(cImage) VALUES(replicate(cast(newID() as VARCHAR(max)),5)) -- 180
    INSERT INTO tableClusteredWithImageDefault(cImage) VALUES(replicate(cast(newID() as VARCHAR(max)),1000)) -- 36000
    INSERT INTO tableClusteredWithImageInline(cImage) VALUES(replicate(cast(newID() as VARCHAR(max)),5))
    INSERT INTO tableClusteredWithImageInline(cImage) VALUES(replicate(cast(newID() as VARCHAR(max)),1000))
    SET @i = @i + 1
  END
  COMMIT TRANSACTION
END

The following query looks at the three possible types of allocation units (especially IN_ROW_DATA for data stored in the table and LOB_DATA for large external data. The third type, ROW_OVERFLOW_DATA, is not used in this example):

select o.name AS tablename, au.type_desc, CEILING(au.used_pages * 8 /1024.0) as usedMB,
       au.data_pages, au.used_pages, au.total_pages, p.partition_number, p.rows,
       au.used_pages * 8 * 1024 / p.rows as [bytes/row]
FROM sys.allocation_units AS au
  JOIN sys.partitions AS p ON au.container_id = p.hobt_id
  JOIN sys.objects AS o ON p.object_id = o.object_id
WHERE o.name like 'table%';

The result shows as expected where the data is stored (keep in mind the average length for the rows includes long and short rows).

tablename                       type_desc       usedMB    data_pages  used_pages   total_pages  rows  bytes/row
tableHeapWithImageDefault       IN_ROW_DATA          5    582         586          587          100000       48
tableHeapWithImageDefault       LOB_DATA          1778    0           227574       227611       100000    18642
tableHeapWithImageInline        IN_ROW_DATA         16    1961        1971         1971         100000      161
tableHeapWithImageInline        LOB_DATA          1758    0           225003       225035       100000    18432
tableClusteredWithImageDefault  IN_ROW_DATA          5    582         586          587          100000       48
tableClusteredWithImageDefault  LOB_DATA          1778    0           227574       227611       100000    18642
tableClusteredWithImageInline   IN_ROW_DATA         16    1961        1971         1971         100000      161
tableClusteredWithImageInline   LOB_DATA          1758    0           225003       225043       100000    18432

So now we can also record the data pages used for the allocation units so we can verify after conversion that the data has actually not been touched (idea):

select o.name, au.allocation_unit_id, au.type_desc, au.total_pages, au.first_iam_page, au.first_page, au.root_page
from sys.system_internals_allocation_units au
  JOIN sys.system_internals_partitions AS p ON au.container_id = p.partition_id
  JOIN sys.objects AS o ON p.object_id = o.object_id
WHERE o.name like 'table%';

With the following result:

name                           allocation_unit_id type_desc    total   first_iam_page first_page     root_page
tableHeapWithImageDefault      72057594197966848  IN_ROW_DATA  587     0x3DB302000100 0x3CB302000100 0x748707000100
tableHeapWithImageDefault      72057594198032384  LOB_DATA     227611  0x3BB302000100 0x38B302000100 0x38B302000100
tableHeapWithImageInline       72057594198097920  IN_ROW_DATA  1971    0xB91507000100 0x2E8B06000100 0x3FDA00000100
tableHeapWithImageInline       72057594198163456  LOB_DATA     225035  0x478707000100 0x418707000100 0x418707000100
tableClusteredWithImageDefault 72057594198228992  IN_ROW_DATA  587     0x4F8707000100 0x4E8707000100 0x768707000100
tableClusteredWithImageDefault 72057594198294528  LOB_DATA     227611  0x4D8707000100 0x4C8707000100 0x4C8707000100
tableClusteredWithImageInline  72057594198360064  IN_ROW_DATA  1971    0x558707000100 0x548707000100 0x4FDA00000100
tableClusteredWithImageInline  72057594198425600  LOB_DATA     225043  0x578707000100 0x568707000100 0x568707000100

So and now finally we can alter the columns:

SET STATISTICS TIME ON
ALTER TABLE tableHeapWithImageDefault ALTER COLUMN cImage VARBINARY(MAX);
ALTER TABLE tableHeapWithImageInline ALTER COLUMN cImage VARBINARY(MAX);
ALTER TABLE tableClusteredWithImageDefault ALTER COLUMN cImage VARBINARY(MAX);
ALTER TABLE tableClusteredWithImageInline ALTER COLUMN cImage VARBINARY(MAX);
SET STATISTICS TIME OFF

And this returns in elapsed time = 0ms with the following new data layout. What is visible at first is that it has generated empty ROW_OVERFLOW_DATA allocation units for all rows (this might indicate that the conversion could differ if the rows are (nearly) full, which is not the case for our narrow tables in the experiment).

name                           allocation_unit_id type_desc          total first_iam_page first_page     root_page
tableHeapWithImageDefault      72057594197966848  IN_ROW_DATA          587 0x3DB302000100 0x3CB302000100 0x748707000100
tableHeapWithImageDefault      72057594198032384  LOB_DATA          227611 0x3BB302000100 0x38B302000100 0x38B302000100
tableHeapWithImageDefault      72057594198491136  ROW_OVERFLOW_DATA      0 0x000000000000 0x000000000000 0x000000000000
tableHeapWithImageInline       72057594198097920  IN_ROW_DATA         1971 0xB91507000100 0x2E8B06000100 0x3FDA00000100
tableHeapWithImageInline       72057594198163456  LOB_DATA          225035 0x478707000100 0x418707000100 0x418707000100
tableHeapWithImageInline       72057594198556672  ROW_OVERFLOW_DATA      0 0x000000000000 0x000000000000 0x000000000000
tableClusteredWithImageDefault 72057594198228992  IN_ROW_DATA          587 0x4F8707000100 0x4E8707000100 0x768707000100
tableClusteredWithImageDefault 72057594198294528  LOB_DATA          227611 0x4D8707000100 0x4C8707000100 0x4C8707000100
tableClusteredWithImageDefault 72057594198622208  ROW_OVERFLOW_DATA      0 0x000000000000 0x000000000000 0x000000000000
tableClusteredWithImageInline  72057594198360064  IN_ROW_DATA         1971 0x558707000100 0x548707000100 0x4FDA00000100
tableClusteredWithImageInline  72057594198425600  LOB_DATA          225043 0x578707000100 0x568707000100 0x568707000100
tableClusteredWithImageInline  72057594198687744  ROW_OVERFLOW_DATA     0  0x000000000000 0x000000000000 0x000000000000

And on the second glance we notice that neither the AU unit ID nor the page addresses has changed for any of the IN_ROW_DATA or LOB_DATA. So this means the change from IMAGE to VARBINARY(max) is low impact for the tested cases.

When turning on the out_of_row setting for the table(Heap/Clustered)WithDefault tables (which had no inline data before) the situation does not change. The elapsed time = 0ms and the result is unchanged:

SET STATISTICS TIME ON
exec sp_tableoption 'tableHeapWithImageDefault', 'large value types out of row', '1';
exec sp_tableoption 'tableClusteredWithImageDefault', 'large value types out of row', '1';
SET STATISTICS TIME OFF

Results in this (removed overflows):

name                           allocation_unit_id type_desc   total_pages first_iam_page first_page     root_page
tableHeapWithImageDefault      72057594197966848  IN_ROW_DATA 587         0x3DB302000100 0x3CB302000100 0x748707000100
tableHeapWithImageDefault      72057594198032384  LOB_DATA    227611      0x3BB302000100 0x38B302000100 0x38B302000100
tableClusteredWithImageDefault 72057594198228992  IN_ROW_DATA 587         0x4F8707000100 0x4E8707000100 0x768707000100
tableClusteredWithImageDefault 72057594198294528  LOB_DATA    227611      0x4D8707000100 0x4C8707000100 0x4C8707000100

Running the same option (elasped 15ms) change on the previously inlined-enabled tables:

SET STATISTICS TIME ON
exec sp_tableoption 'tableClusteredWithImageInline', 'large value types out of row', '1';
exec sp_tableoption 'tableHeapWithImageInline', 'large value types out of row', '1';
SET STATISTICS TIME OFF

With the unchanged pages:

name                          allocation_unit_id type_desc   total_pages first_iam_page first_page     root_page
tableHeapWithImageInline      72057594198097920  IN_ROW_DATA 1971        0xB91507000100 0x2E8B06000100 0x3FDA00000100
tableHeapWithImageInline      72057594198163456  LOB_DATA    225035      0x478707000100 0x418707000100 0x418707000100
tableClusteredWithImageInline 72057594198360064  IN_ROW_DATA 1971        0x558707000100 0x548707000100 0x4FDA00000100
tableClusteredWithImageInline 72057594198425600  LOB_DATA    225043      0x578707000100 0x568707000100 0x568707000100

So even that change has no impact. According to MSDN the reason for this is that the LOBs are only changed when updated. So this is also quite safe.

The same should be true for the other way around, however I have seen cases, where it took much longer with lots of logfile usage. Maybe you have an idea how I can recreate this scenario?

Search Meetup Karlsruhe

Search User Group KA LogoLetzte Woche fand das erste Meetup der neuen Search Meetup Gruppe in der IHK statt. Die Auftaktveranstaltung war gesponsort* von Exensio. Florian und Tobias die Organisatoren konnten einige Search-Begeisterte aus dem Raum Karlsruhe zusammenbekommen um die zukünftigen Themen des Meetups zu besprechen. Tobias ielt den ersten Kurzvortrag (den ich leider verpasst hatte). Anschliessend gab es noch angeregte Diskussionen um zukünftige Themen. Solange aus den unterschiedlichsten Unternehmen die rund um Karlsruhe Such Technologien (wie Lucene, Elastic Search oder Solr) einsetze Vortragsangebote kommen, sollten auch künftige Meetups spannend werden.

Twitter: @SearchKA
Meetup Gruppe: Search Meetup Karlsruhe

 * Es scheint garnicht zu einfach sein in der Technologie Region Karlsruhe kostenfrei Räumlichkeiten für UserGroups zu erhalten. Hier sollten sich die diversen Marketing-Arme der Stadt und "High Tech Industrie" mal was überlegen.

Oracle Container Datenbank

Seit einiger Zeit gibt es eine Neuauflage des SQL Datenbankklassikers von Oracle. Unter der Bezeichnung Oracle 12c (C wie Cloud) und der internen Versionsnummer 12.1 stehen einige neue Funktionen bereit.

Multitenant Architectur (CDB) 

Mit der 12c Release hat Oracle eine neue Multitenant Architektur eingeführt, die es erlaubt eigenständig verwaltbare Datenbanken in einer gemeinsamen Datenbankinstanz zu betreiben. Damit verbunden sind einige neue Features wie der Transport der gesamten Datenbank (nicht nur einzelner Tablespaces) von einer Instanz in eine andere. Es erlaubt ebenfalls das bereitstellen von Clones der Datenbank für Entwicklung und QA. Das Hauptargument ist jedoch die Selbstverwaltung durch beschränken der Sichtbarkeit der Datenbankobjekte auf den jeweiligen Untermieter - alles was man für die Konsolidierung von Datenbanken so braucht.

Damit zieht Oracle mit dem Microsoft SQL Server gleich, bei dem Datenbanken ja schon länger eigenständige Objekte (mit eigenen Usern) waren. Allerdings wirkt es wie gewohnt bei Oracle etwas aufgesetzter. So gibt es die normalen Systemuser die in allen PDB gelten (z.B. DBSNMP) aber für weitere User empfiehlt Oracle eine Namenskonvention "C##USERNAME" für gemeinsam benutzte (Common) User.

Meiner Erfahrung nach heißt es Vorsicht beim Umstieg auf 12c (wenn die CDB aktiviert ist). Die neue Multitenant Architektur ist zwar praktisch, DBA sind es aber nicht gewöhnt. So ist es z.B. wichtig vorhandene User+Rollen Definitionsscripte entweder im richtigen Container aufzurufen. Entweder man benutzt einen Common DB User und ändert den Session Context:

ALTER SESSION SET CONTAINER = 'PDBTEST'; 

Dann muss man sich aber auch regelmäßig vergewissern, welches die gerade aktive PDB ist:

SELECT SYS_CONTEXT('USERENV', 'CON_NAME') FROM DUAL;

Oder man legt entsprechende Administrationuser in jeder PDB separat an. Dazu muss man dann auch einen TNS Connect String verwenden der auf einen Datenbank Service verweist, welcher der jeweiligen PDB zugeordnet ist. Wenn eine neue PDB angelegt wurde, wird auch ein neuer Service mit PDB Name + DB_Domain registriert:

> SELECT NAME,PDB,CON_ID from GV$SERVICES;
NAME                         PDB                  CON_ID
---------------------- -------------------------- ----------
pdbtest.eckenfels.net   PDBTEST                   4
pdborcl.eckenfels.net   PDBORCL                   3
orcl.eckenfels.net      CDB$ROOT                  1
SYS$BACKGROUND          CDB$ROOT                  1
SYS$USERS               CDB$ROOT                  1  

Die Arbeit mit CDBs macht Oracle nicht gerade einfach. Wenn man eine neue Container Datenbank mit dem Datebank Konfigurationsassistent (oder CREATE Statement) anlegt, so wird diese Datenbank bei einem Instanzstart nicht automatisch geöffnet. Man muss sich also mit einem Systemtrigger behelfen. Das hätte man wirklich komfortabler lösen können (und wenn Oracle in einer nächsten Version eine Lösung dafür anbietet wird man sich mit den Triggern wieder beschäftigen müssen).

Das ist übrigens ein sehr ärgerliches Problem, der Oracle SQL Developer gibt zwar in der Console eine entsprechende Fehlermeldung aus:

> ALTER SESSION SET container = PDBORCL;
session SET geändert.
> CREATE ROLE "NORMAL_USER";
Fehler beim Start in Zeile 1 in Befehl:
CREATE ROLE "NORMAL_USER"
Fehler bei Befehlszeile:1 Spalte:1
Fehlerbericht:
SQL-Fehler: ORA-01109: Datenbank nicht geöffnet
01109. 00000 -  "database not open"
*Cause:    A command was attempted that requires the database to be open.
*Action:   Open the database and try the command again
> ALTER PLUGGABLE DATABASE PDBORCL OPEN READ WRITE;
pluggable DATABASE geändert.
> CREATE ROLE "NORMAL_USER";
role "NORMAL_USER" erstellt.

Wenn man das ganze allerdings im SQL Developer macht, so wird die Meldung durch ein Fehler Pop-Up mit unverständlicher Fehlermeldung verdeckt:

Bei der Ausführung des angeforderten Vorgangs ist ein Fehler aufgetreten:
ORA-06550: Zeile 3, Spalte 35:
PLS-00201: Bezeichner 'DBMS_SQL.OPEN_CURSOR' muss deklariert werden
ORA-06550: Zeile 3, Spalte 19:
PL/SQL: Item ignored
ORA-06550: Zeile 13, Spalte 26:
PLS-00320: Die Typ-Deklaration dieses Ausdruckes ist unvollständig oder fehlerhaft
ORA-06550: Zeile 13, Spalte 9:
PL/SQL: Statement ignored
ORA-06550: Zeile 16, Spalte 17:
PLS-00201: Bezeichner 'DBMS_SQL.LAST_ERROR_POSITION' muss deklariert werden
ORA-06550: Zeile 16, Spalte 5:
PL/SQL: Statement ignored
ORA-06550: Zeile 18, Spalte 34:
PLS-00320: Die Typ-Deklaration dieses Ausdruckes ist unvollständig oder fehlerhaft
ORA-06550: Zeile 18, Spalte 11:
PL/SQL: Statement ignored
06550. 00000 -  "line %s, column %s:\n%s"
*Cause:    Usually a PL/SQL compilation error.
*Action:
Herstellercode 6550

Eine gute Zusammenfassung aller CDB spezifischen Punkte findet sich im Oracle Database Administrator's Guide im Kapitel 40 Administering a CDB with SQL*Plus

Enterprise Manager Database Express

Eine neue Funktion ist das Enterprise Manager Database Express Modul. Statt einen abgespeckten Enterprise Manager (Database Control) mit eigenem Prozess und Ablaufumgebung zu installieren kann man das in der Datenbank eingebaute Express Modul verwenden. Dieses basiert auf der AppEx Infrastruktur. Das als Performance Hub getaufte Dashboard profitiert dann auch mit den Offline abspeicherbaren HTML Reports. Ansonsten ist die Funktionalität allerdings sehr eingeschränkt. Es gibt z.B. keine DDL Funktionen zum Anlegen oder verwalten von Tabellen.

EM DB Express unterstützt die Verwendung von Plugable Databases dahingehend, dass man für jeden Tenant ein eigener http oder https Listener (Port) anlegen kann. Wenn man sich dann nicht im Root Container anmeldet, so sieht man dann erst die jeweils in der PDB angelegten User (Und leider nur dann).

> select dbms_xdb_config.gethttpsport from dual;
GETHTTPSPORT
------------
5500
> alter session set container = PDBTEST;
> select dbms_xdb_config.gethttpsport from dual;
GETHTTPSPORT
------------
> exec DBMS_XDB_CONFIG.SETHTTPSPORT(5502);
> select dbms_xdb_config.gethttpsport from dual;
GETHTTPSPORT
------------
5502

Wenn man sich mit einer PDB verbunden hat (in meinem Beispiel https://server:5502/em/) so wird in der Titelzeile des EM Express links oben nicht nur die SID, sondern auch den Namen der PDB angezeigt. Ebenso enthält die Userliste nicht mehr (nur) die Gemeinsamen User:

Oracle JDBC Ping Database

Oracle hat im JDBC Treiber (und dem eigenen Connection Pool) jede Menge Funktionen eingebaut, die über das Verhalten von JDBC hinausgehen. Oftmals wird dies mit Performance-Vorteilen begründet. Man sollte diese Feature (nicht nur aus Kompatibilitätsgründen) nicht ungeprüft übernehmen, zum Beispiel hat JBoss AS einen OracleValidConnectionChecker, der mittels Relfection die Oracle Spezialfunktion pingDatabase() verwendet. Alternativ gibt es eine generische Implementierung, die einfach ein Statement absetzt. Die Prüfung ob eine DB connection noch funktioniert (entweder regelmässig im Hintergrund oder bei jedem ausleihen aus dem Pool) ist recht wichtig für einen stabilen Systembetrieb - aber auch sehr Performancerelevant. Mit pingDatabase würde man so vorgehen: Wenn man aber die Implementierung analysiert, so stellt man schnell fest, dass die aktuelle Version des Treibers hier nicht sonderlich effizient implementiert ist. Es wird das SQL Statement "SELECT 'X' FROM DUAL" abgesetzt. (Immerhin wird dazu vorher der Rückgabetyp deklariert: ((OracleStatement)stmt).defineColumnType (1, Types.CHAR, 1);) Es wird kein prepared statement eingesetzt, dass heisst der Datenbank Server muss bei jedem Aufruf das Statement mühsam parsen. Wenn ein Timeout angegeben wurde, so startet der JDBC Treiber bei jedem Ping einen neuen Thread. Auf die timeout Funktion sollte also auf jeden Fall verzichtet werden (Oracle hat diese Variante auch deprecated).

Oracle OTN Downloads auf HP/UX Server

Leider macht es Oracle recht schwer die Archive für den Datenbank Install aus dem Oracle Technology Network ohne (grafischen) Web Browser herunterzuladen: Man muss angemeldet sein und den Lizenzbedingungen zustimmen. Dabei wird nicht nur JavaScript eingesetzt sondern auch ein Session Cookie verwendet. Das macht die Verwendung von wget - auch wenn man die download URL kennt - leider nicht möglich. Neben dem Herunterladen auf ein internes System mit grafischem Browser ist es stattdessen möglich entweder auf dem Zielserver einen Command-Line Browser zu verwenden der auch Cookies (und SSL) unterstützt oder eben wget auf dem Zielserver und vorher die Cookies mittels Command Line browser ermitteln. Aktuell teste ich Software auf den HP/UX Servern im HP Partnerprogramm PVP. Diese Server sind recht minimalistisch ausgestattet. Um dort einen SSL fähigen Command-Line Browser zu erhalten benutze ich das Links Paket. Es benötigt Perl und OpenSSL als Abhängigkeiten und wird im Software Depot des HP Porting Centers angeboten (Dort gibt es zwar auch ein Lynx Paket mit weniger Dependencies, das ist allerdings ohne SSL Unterstützung). Einfacherweise installiert man sich zuerst den depothelper vom Porting Center. Dieser übernimmt den restlichen Download, das Auspacken und Installieren des Paketes und aller Abhängigkeiten:
# uname -a HP-UX server B.11.31 U ia64 3663751510 unlimited-user license # cd /var/tmp # ftp hpux.connect.org.uk User: ftp Pass: root@ ftp> cd /hpux/Sysadmin/depothelper-2.00/ ftp> get depothelper-2.00-ia64-11.31.depot.gz ftp> quit # /usr/contrib/bin/gunzip depothelper-2.00-ia64-11.31.depot.gz the next command requires an absolute path # swinstall -s /var/tmp/depothelper-2.00-ia64-11.31.depot depothelper now you can use depothelper to install a package with dependencies # /usr/local/bin/depothelper links ================================================ Package-version Comment Download Install ================================================ ia64-11.31 Package list OK OK db-5.0.26 Dependency (01/07) OK OK (+ deleted depot) expat-2.0.1 Dependency (02/07) OK OK (+ deleted depot) gdbm-1.8.3 Dependency (03/07) OK OK (+ deleted depot) gettext-0.18 Dependency (04/07) OK OK (+ deleted depot) libiconv-1.13.1 Dependency (05/07) OK OK (+ deleted depot) openssl-1.0.0a Dependency (06/07) OK OK (+ deleted depot) perl-5.10.1 Dependency (07/07) OK OK (+ deleted depot) links-1.00pre23 Requested OK OK (+ deleted depot) ================================================
Wenn auf dem Server kein Links (mit Perl installiert werden soll, so gibt es auch Tipps wie man den Login auf OTN mit einem Lynx Browser auf einem Testsystem absolvieren kann und die dabei erhaltenen gültigen Cookies per File dann an wget auf dem Zielserver weiterreichen kann. Dies ist hier näher beschrieben.

Oracle@EC2

Oracle und Amazon arbeiten zusammen um Oracle Anwendungen im Amazon Grid anzubieten. Es gibt jetzt einige Images die von Oracle kostenlos bereitgestellt werden. Oracle erlaubt sogar den Betrieb von Produktiven lizenzierten Anwendungen im EC2 Grid. Die Konfiguration ist sogar für offiziellen Support zertifiziert. Besonders interessant sind aber auch die Möglichkeiten die vorinstallierten Anwendungen wie Application Express oder Enterprise Manager Grid einfach mal ausprobieren zu können.

SQL Developer Reports: Segment Size

Ein nettes Feature beim Oracle SQL Developer ist die Möglichkeit einfachere oder komplexere SQL Statements als Reports zu hinterlegen und dann laufen zu lassen. Visualisierung in Form von Tabellen oder Grafiken mit inbegriffen.
Report: Usage Segment Size
In lockerer Folge möchte ich einige der Reports vorstellen die ich so einsetze. Heute der "Segment Size" Report, der eine Liste aller Segmente (eines Owners) erstellen kann, und diese nach Platzbedarf sortiert. Dabei werden für die Typen TABLE, INDEX und LOB* Details ausgegeben (also insbesondere zu welcher Tabelle das LOB oder Index Segment gehört, und welche Spalten es abdeckt). Beim Start des Reports kann man den Owner (Schema User) angeben, für den man sich interessiert. Es wird hier ein substring vergleich verwendet, also bei der Eingabe von SYS (wie im Screenshot) werden die Ausgaben gruppiert nach mehreren Ownern gemacht. Hier als Beispiel, der Index der im SYS Schema den meisten Raum belegt hat den Segment Namen "I_WRI$_OPTSTAT_H_OBJ#_ICOL#_ST" und er ist auf der Tabelle "WRI$_OPTSTAT_HISTGRM_HISTORY" im Tablespace SYSAUX angelegt. Der Index hat 3 Spalten, im Report wird nur die erste und letzte ausgegeben: "3: INTCOL#,SYS_NC00013$". Dies ist eine Einschränkung, weil es keine portable String Aggregationsfunktion gibt. Eventuell will sich jemand die Mühe machen dies auf mehr Spalten auszubauen? Die Größenangabe des Segments (in Extends und Megabytes) basiert auf den Spalten bytes und extends aus dem DBA_SEGMENTS view. Entspricht also dem Platzverbrauch aber nicht dem Füllstand. Ausgelassen werden Recylce Objekte. Der Report sollte mit allen Oracle Database Versionen lauffähig sein, das Export File ist im SQL Developer 1.5 Format. eckes-sqldeveloper.xml

Es menschelt bei Panta Rhei (SOA vs. SQL)

Drüben im virtuellen Blog des fiktiven EDV Leiters Frank Bremer menschelt es. Intrigen und Aus-dem-Bauch Entscheidungen bestimmen den Alltag (das ist allzu realistisch .). Gerade ging es in einem Artikel darum, den CFO von seiner Anti-SOA Meinung (die er durch einen polarisierenden Artikel gefasst hat) durch den Google Zeitgeist abzubringen: wie groß ist der SOA Hype? Dieser Blog Post hat mich motiviert selbst einmal einige Zeitgeist Trends gegenüberzustellen. Und bin dabei auf ein sehr interessantes (unerwartetes) Ergebnis gestoßen: SOA vs. SQL at Google Trends Danach gibt es um Größenordnungen mehr Anfragen zum Thema SQL als zum Thema SOA, dafür berichtet die Schreibende Zunft deutlich stärker über den Hype. Es ist wohl unstrittig, dass SQL (Netzwerk) Datenbanken zu einem Paradigmenwechsel in der IT geführt haben. Und der Fieberkurve nach zu urteilen auch sehr nachhaltig. Das muß an dem hohen integrativen Potential von offenen Datenschnittstellen liegen. Nicht umsonst nennt man SOA das SQL des neuen Jahrhunderts. Mal sehen ob das EA Modell dem auch gerecht werden kann. Aber gut, im Vergleich zu anderen Schlagwörtern ist SOA schon Alltag*: SOA vs. Corba at Google Trends * Ich fühle mich Unwohl dem Google Zeitgeist zu viel Bedeutung zuzumessen, aber wenn das Herr Müller Dreist überzeugt, sollte es auch meine Leser täuschen können :)

Chaos...

Isolation: Chaos Am Wochenende waren meine Frau und ich im Kino, und konnten uns schön die Vorstellung von Chaos (verursacht durch Dark Phoenix) in den Köpfen eines CGI Gestalters ansehen. Und dann stolpere ich am Abend doch glatt schon wieder im SQLCode Blog über ein halbwegs On-Topic Bild zum Thema Chaos (und Microsoft SQL Server).

Oracle SQL Developer

In der Software Entwicklung von DB verbundenen Systemen hat man immer die Notwendigkeit auch manuell mit der Datenbank Verbindung aufzubauen, SQL Statements abzusetzen oder auch mal in den DB Objekten zu browsen. Oftmals kommen hier Tools zum Einsatz. Im Oracle Umfeld dürfte TOAD hier am bekanntesten sein.
Oracle SQL Developer
Integrierte Entwicklungsumgebungen wie Eclipse oder Oracle JDeveloper haben eigene Funktionen für den Zugriff auf Datenbanken. Diese sind aber nicht immer sehr effizient und komplett zu nutzen. Oracle hat den SQL Developer veröffentlicht. Es ist eine Entwicklungsumgebung reduziert auf die Manipulation von SQL insbesondere auch PL/SQL Statements und Packages. Ein Teil der SQL Developer Funktionen wurden auch in den Oracle JDeveloper übernommen. "Oracle SQL Developer" vollständig lesen

When I am sixty-four

Die Beatles Zeile war auch der Titel einer Blog-Post im SAP Developer Network. Deswegen möchte ich hier auch noch mal berichten, dass so langsam der 64-bit Durchbruch stattfindet. 32-bit Kernel für AIX auf Power oder Solaris auf Sparc sind schon lange ein Seltenheit, jetzt ziehen auch Anwendungen und weitere Betriebsysteme nach: Durch den starken Support der Platform Hersteller und interpretierten code (.NET, Java oder ABAP) ist der 64-bit Übergang einfacher und schmerzloser als erwartet. Aktuell allerdings bedeutet es für Administratoren und Entwickler aber zusätzlichen Support und Test Aufwand. Wie sieht denn die Zukunft bei Oracle aus? Mit 10.2 gibt es jedenfalls keine 32-bit Versionen des Datenbank Servers für die POWER oder UltraSPARC Architektur. Inwzischen ist auch die Solaris x64 Lücke geschlossen: seit dem 23. März sind die AMD64 Binaries in 64-bit Breite erhältlich. Somit bleibt nur Windows und Linux auf x86 - was für eine Neuinstallation ohnehin keinen Sinn mehr macht.

OCFS2 certified for Oracle 10g RAC

Gerade kommt über die OCFS2 User Mailingliste die Ankündigung herein, dass OCFS2 1.2.1 released wurde, und im Zusammenspiel mit RHEL4 auf x86 Linux von Oracle Database 10gR2 für den Produktiveinsatz freigegeben wurde. Gerade in letzter Zeit häuften sich Probleme mit instabilen Treibern (SAN, Firewire, iSCSI), so dass es ziemlich klar ist, dass es sehr leichtsinnig wäre ein OCFS2 Cluster zu betreiben ohne sich strikt an zertifizierte Kernels (und Hardware) zu halten. In vielen Fehlersituationen schaltet OCFS2 Knoten ab um den Konflikt zu lösen (z.B. wenn die Netzwerkverbindung abbricht, oder kein konstanter Kontakt mit den Platten vorhanden ist). Dieses Fencing (abtrennen vom Zugriff auf das Shared Storage durch Shutdown) macht das Debuggen nicht einfacher. Es empfiehlt sich also bei sporadischem Shutdown eine Netconsole zu betreiben, um Post-Mortem die Diagnose-Meldungen der Kernel Module zu erhalten. Update: Interessanterweise ist in den Oracle Blogs nichts zu dem Thema zu finden: Search: ocfs2, auch die Blogsphere ist sehr verhalten: Technorati: ocfs2