1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
WITH btree_index_atts AS ( SELECT nspname, relname, reltuples, relpages, indrelid, relam, regexp_split_to_table(indkey::text, ' ')::smallint AS attnum, indexrelid as index_oid FROM pg_index JOIN pg_class ON pg_class.oid=pg_index.indexrelid JOIN pg_namespace ON pg_namespace.oid = pg_class.relnamespace JOIN pg_am ON pg_class.relam = pg_am.oid WHERE pg_am.amname = 'btree' ), index_item_sizes AS ( SELECT i.nspname, i.relname, i.reltuples, i.relpages, i.relam, s.starelid, a.attrelid AS table_oid, index_oid, current_setting('block_size')::numeric AS bs, /* MAXALIGN: 4 on 32bits, 8 on 64bits (and mingw32 ?) */ CASE WHEN version() ~ 'mingw32' OR version() ~ '64-bit' THEN 8 ELSE 4 END AS maxalign, 24 AS pagehdr, /* per tuple header: add index_attribute_bm if some cols are null-able */ CASE WHEN max(coalesce(s.stanullfrac,0)) = 0 THEN 2 ELSE 6 END AS index_tuple_hdr, /* data len: we remove null values save space using it fractionnal part from stats */ sum( (1-coalesce(s.stanullfrac, 0)) * coalesce(s.stawidth, 2048) ) AS nulldatawidth FROM pg_attribute AS a JOIN pg_statistic AS s ON s.starelid=a.attrelid AND s.staattnum = a.attnum JOIN btree_index_atts AS i ON i.indrelid = a.attrelid AND a.attnum = i.attnum WHERE a.attnum > 0 GROUP BY 1, 2, 3, 4, 5, 6, 7, 8, 9 ), index_aligned AS ( SELECT maxalign, bs, nspname, relname AS index_name, reltuples, relpages, relam, table_oid, index_oid, ( 2 + maxalign - CASE /* Add padding to the index tuple header to align on MAXALIGN */ WHEN 2%maxalign = 0 THEN maxalign ELSE 2%maxalign END + nulldatawidth + maxalign - CASE /* Add padding to the data to align on MAXALIGN */ WHEN nulldatawidth::integer%maxalign = 0 THEN maxalign ELSE nulldatawidth::integer%maxalign END )::numeric AS nulldatahdrwidth, pagehdr FROM index_item_sizes AS s1 ), otta_calc AS ( SELECT bs, nspname, table_oid, index_oid, index_name, relpages, coalesce( ceil((reltuples*(4+nulldatahdrwidth))/(bs-pagehdr::float)) + CASE WHEN am.amname IN ('hash','btree') THEN 1 ELSE 0 END , 0 -- btree and hash have a metadata reserved block ) AS otta FROM index_aligned AS s2 LEFT JOIN pg_am am ON s2.relam = am.oid ), raw_bloat AS ( SELECT current_database() as dbname, nspname, c.relname AS table_name, index_name, bs*(sub.relpages)::bigint AS totalbytes, CASE WHEN sub.relpages <= otta THEN 0 ELSE bs*(sub.relpages-otta)::bigint END AS wastedbytes, CASE WHEN sub.relpages <= otta THEN 0 ELSE bs*(sub.relpages-otta)::bigint * 100 / (bs*(sub.relpages)::bigint) END AS realbloat, pg_relation_size(sub.table_oid) as table_bytes, stat.idx_scan as index_scans FROM otta_calc AS sub JOIN pg_class AS c ON c.oid=sub.table_oid JOIN pg_stat_user_indexes AS stat ON sub.index_oid = stat.indexrelid ) SELECT dbname as database_name, nspname as schema_name, table_name, index_name, round(realbloat, 1) as bloat_pct, wastedbytes as bloat_bytes, pg_size_pretty(wastedbytes) as bloat_size, totalbytes as index_bytes, pg_size_pretty(totalbytes) as index_size, table_bytes, pg_size_pretty(table_bytes) as table_size, index_scans FROM raw_bloat WHERE ( realbloat > 50 and wastedbytes > 50000000 ) ORDER BY wastedbytes DESC; |
Archiv des Autors: Markus Wollny
PostgreSQL: stats_temp_directory auf RAMDisk
Link
Putting stats_temp_directory on a ramdisk – schnelle und billige Perfomance-Optimierung; wieviel das im Einzelfall bringt ist unterschiedlich, speziell VACUUM sollte davon aber durchaus profitieren.
JavaScript-Debugging
Link
Lesser-Known JavaScript Debugging Techniques
Debug Utils, dazu die zugehörige Chrome-Extension.
IVW-Zählung: Übertragungsmodus richtig setzen
Link
Link: Die Top 4 JavaScript Sünden des neuen IVW Pixels
tl;dr: Der Default-Übertragungsmodus für SZM KAT 2.0- und FRABO-Tag ist grenzdebil (document.write), stattdessen sollte der appendChild()-Modus gesetzt werden, indem man die beiden Methodenaufrufe wie folgt anpasst:
SZM-Tag 2.0 (Übertragungsmodus): iom.c(iam_data) => iom.c(iam_data,1) somit wird eine appendChild()-Methode aus dem SZM-Tag.
FRABO: “sv”:”in” => “sv”:”i2″ – somit wird der FRABO, genau wie der SZM-Tag 2.0 per appendChild()-Methode ausgespielt.
Hier der Vollständigkeit halber noch die Links zur Dokumentation für SZM-Kat 2.0 und FRABO.
Ist jQuery zu groß für Mobile?
Link
http://flippinawesome.org/2014/03/10/is-jquery-too-big-for-mobile/
tl;dr:
There’s Almost Certainly Something Way More Important to the Efficiency of Your Application Than Whether You Use jQuery
Abgesehen von alten (und lahmen) Android-Geräten, die sich sehr lange fürs Parsen von jQuery Zeit lassen, gibt’s meist deutlich mehr Optimierungspotenzial an anderen Stellen.
Effektiveres Multi-Insert mit unnest und CTE
Wir haben eine Tabelle zum Tracking von Suchwörtern, d.h. den Bestandteilen einer Suchphrase:
1 2 3 4 5 6 7 8 9 |
CREATE TABLE stats.tracking_keywords ( id bigserial, keyword text NOT NULL, site_id integer NOT NULL, created timestamp without time zone NOT NULL, user_id integer NOT NULL, CONSTRAINT "pk_t_kw" PRIMARY KEY (id) )WITHOUT OIDS; |
Um jetzt aus einer um Dropwords und bösartigen/dämlichen Blödsinn (nicht druckbare Zeichen, Deppen-Apostrophe, ggf. Satzzeichen) bereinigten Phrase die einzelnen Keywords einzufügen, kann man die Phrase natürlich im Applikationscode an den Leerzeichen splitten und dann in einem Loop die einzelnen Wörter einfügen. Aus einer Suchphrase von drei Wörtern werden dann drei einzelne INSERT-Statements.
Es geht aber auch eleganter.
Weiterlesen
Erzähle-ein-Märchen-Tag: SEO Märchen
Link
Coding Horror: App-pocalypse Now
Link
Coding Horror: App-pocalypse Now.
In violent agreement here.
Window Function Pr0n – und wann man’s besser ohne macht
Es gab SQL vor Window Functions und es gibt SQL nach Window Functions
… so fängt ein lesenwertes Tutorial für dieses Thema an, das beim Einstieg erst einmal recht sperrig ist.
Wenn man sich da aber etwas durchwühlt, dann merkt man wie genial das ganze ist – CTE+Window-Function=Pr0n. Bis man aber dahin kommt, braucht’s einfach erst einmal ein bisschen mehr Brainfuck als im Alltag oft möglich ist. Darum will ich hier mal den allersimpelsten Fall zeigen, weitermachen kann man dann eben z.B. mit dem obengenannten Artikel.
Ich baue eine Suchfunktion für unsere Produktdatenbank. Schnell muss es sein, Prefix-Suche muss unterstützt werden, es wird natürlich paginiert. Also brauche ich nicht nur die aktuell dargestellten Produkte, sondern auch immer eine Gesamtzahl.
Weiterlesen
YeSQL: Data-Aggegation in PostgreSQL und MongoDB
Link
CTE, Custom-Aggregate und Window-Funktionen – in MongoDB muss vielen zu Fuß gebaut werden, was in PostgreSQL einfacher und verständlicher verfügbar ist.
Aggregating NBA data, PostgreSQL vs MongoDB
Andererseits: Äpfel und Birnen – manchmal ist eine InMemory-NoSQL-Datenbank doch das bessere Tool für den Job. Ich fühle mich allerdings nach wie vor in SQL und pl/pgSQL, pl/pgPERL etc. wesentlich wohler als in der Map/Reduce-Aggregat-Pipe-Welt von Mongo – vor allem wenn ich nach Monaten etwas am Code anpassen muss.