January 27, 2010

Не используемые индексы

Данный запрос предназначен для выявления индексов претендентов на удаление. В начале отображаются наиболее редко используемые большие индексы.

Запрос действует только по пользовательским индексам и не принимает во внимание уникальные, т.к. они используются как ограничения (как часть логики хранения данных). Тем не менее прежде чем принять решение об удалении хорошо подумайте.

SELECT
idstat.schemaname AS sch, -- схема
idstat.relname AS tab, -- таблица
indexrelname AS idx, -- индекс
idstat.idx_scan AS iis, -- число сканирований по этому индексу
pg_size_pretty(pg_relation_size(indexrelid)) AS isize, -- размер индекса
tabstat.idx_scan AS tis, -- индексных чтений по таблице
tabstat.seq_scan AS tss, -- последовательных чтений по таблице
tabstat.seq_scan + tabstat.idx_scan AS tre, -- чтений по таблице
n_tup_upd + n_tup_ins + n_tup_del AS twr, -- операций записи
pg_size_pretty(pg_relation_size(idstat.relid)) AS tsize -- размер таблицы
FROM
pg_stat_user_indexes AS idstat
JOIN pg_indexes ON
indexrelname = indexname AND
idstat.schemaname = pg_indexes.schemaname
JOIN pg_stat_user_tables AS tabstat ON
idstat.relid = tabstat.relid
WHERE
indexdef !~* 'unique'
ORDER BY
idstat.idx_scan,
pg_relation_size(indexrelid) DESC
LIMIT 20;

January 24, 2010

Индикатор раскладки клавиатуры xxkb в Xmonad

Итак, есть Xmonad, требуется индикатор раскладки клавиатуры отображающийся в правом верхнем углу экрана и запоминающий раскладку для каждого окна.

Прежде всего устанавливаем расширение клавиатурного модуля xxkb, позволяющее отображать раскладки, менять их, и многое другое. Установка специфична для каждого дистрибутива, по этому описывать её тут не буду, если что google в помощь.

Далее добавляем в ~/.xmonad/xmonad.hs его запуск при загрузке:

main = do
...
spawn myXxkbBar
...

myXxkbBar = "xxkb" -- configuration in ~/.xxkbrc


Да, не забываем подрегулировать свои панели (dzen, xmobar, и т.д.) чтобы в правом верхнем углу был свободный квадрат 15x15 пикселей, где и разместится индикатор. Затем указываем, что его необходимо снимать при перезапуске:

-- Do not leave useless conky, dzen and xxkb after restart
((modm, xK_q), spawn "killall conky dzen2 xxkb; xmonad --recompile; xmonad --restart"),


И игнорировать в ManageHook:

myManageHook = composeAll [
resource =? "XXkb" --> doIgnore
]


Почти всё готово, осталось прописать конфигурацию xxkb в ~/.xxkbrc (измените 1265 на ваше разрешение по y минус 15):

XXkb.group.base: 1
XXkb.group.alt: 2
XXkb.mainwindow.appicon: yes
XXkb.mainwindow.geometry: 15x15+1265+0
XXkb.mainwindow.xpm.1: en15.xpm
XXkb.mainwindow.xpm.2: ru15.xpm
XXkb.button.enable: no
XXkb.controls.add_when_start: no
XXkb.controls.add_when_change: yes
XXkb.controls.focusout: yes
XXkb.controls.mainwindow_delete: no


И, вуаля, получаем то, что требовалось:



Подробнее про xxkb на русском можно почитать тут Индикатор-переключатель раскладки клавиатуры XXKB.

Мою последнюю конфигурацию Xmonad и всё её сопровождающее найдёте здесь Xmonad/Config_archive (поищите gray_hemp).

January 23, 2010

Важность очистки статистики

Это маленький но очень важный момент. Если ваш проект интенсивно развивается, то накопленная за долгий период времени внутренняя статистика PostgreSQL зачастую теряет смысл. Так, например, добавление нового индекса или изменение пары запросов меняет темпы накопления и новая ситуация начинает накладываться на старую, из-за чего можно сделать не правильные выводы. Для того чтобы избежать этого неообходимо очищать старые статистические данные перед запросом статистики, если с момента предыдущей очистки были какие-то изменения влияющие на её сбор.

В PostgreSQL для этого существует специальная функция:

SELECT pg_stat_reset();

Заметьте, после очистки возможно потребуется некоторое время для накопления новой статистики.

January 19, 2010

Конфигурация Xmonad

Мои настройки Xmonad (в первом приближении) опубликовали в Xmonad/Config archive, смотрите /gray_hemp's xmonad.hs и /gray_hemp's .conky_timegray_hemp.

Из особенностей: dzen + conky с иcпользованием иконок layout-ов, resizable tall, xmonad shell prompt, urgency popup плюс форматирование status bar-а.

December 6, 2009

Emacs, файлы отката и авто-сохранения

По умолчанию, для файлов которые вы редактируете, Emacs создаёт файлы отката вида filename~ и файлы авто-сохранения вида #filename#. Первые остаются после закрытия файла и зачастую портят эстетическую составляющую вашего рабочего каталога. В этом посте рассматриваются способы решения этой проблемы.

Если вам совсем не нужен функционал резервного копирования, то вы можете просто отключить его.

~/.emacs.d/general.el:

;; Stop creating backup~ and #auto-save# files
(setq make-backup-files nil)
(setq auto-save-default nil)


Если вы всё же беспокоитесь за безопасность ваших данных, то вы столкнётесь со следующей проблемой. По умолчанию Emacs создаёт резервный файл переименованием оригинального, затем создаёт новый файл с оригинальным именем копированием и открывает его. Таким образом время создания файла меняется, даже если вы не меняли содержимое. Что-бы такого не было можно поменять поведение создание резервного файла на обратное.

~/.emacs.d/general.el:

;; Copy original file when creating backup
(setq backup-by-copying t)


По умолчанию резервные файлы хранятся рядом с их оригиналами, но можно указать директорию, где Emacs должен их создавать. В таком случае если оригинальный файл "/home/gray/tmp/sub/file.txt", а директория для резервного копирования "~/.emacs.d/files-backup", то резервный файл будет именован "~/.emacs.d/files-backup/home!gray!tmp!sub!file.txt".

~/.emacs.d/general.el:

;; Set directory for backup files
(setq backup-directory-alist '(("" . "~/.emacs.d/files-backup")))


В выше приведенном случае, если вы используете длинные имена файлов или глубокие пути, может легко быть достигнут лимит длины имён файлов. Эту проблему можно решить переопределив встроенную функцию определения имени резервного файла make-backup-file-name-function своей, которая будет создавать структуру директорий, такую же как от корня до оригинального файла, в директории для резервного копирования. Для выше приведённого примера резервный файл будет "~/.emacs.d/files-backup/home/gray/tmp/sub/file.txt".

~/.emacs.d/general.el:

;; File path mirroring for backup files
(defun my-backup-file-name (fpath)
(let (backup-root bpath)
(setq backup-root "~/.emacs.d/files-backup")
(setq bpath (concat backup-root fpath "~"))
(make-directory (file-name-directory bpath) bpath)
bpath
)
)
(setq make-backup-file-name-function 'my-backup-file-name)


Есть ещё несколько вещей связанных с резервированием и касающихся версионности, но об этом в другом посте.

Начальная настройка Emacs

Решил привести в систематизированный вид конфигурацию своего Emacs. В связи с этим решил написать несколько постов с рекомендациями для начинающих "эмаксоидов" о его настройке с нуля, а так как я от выше упомянутых ещё не далеко ушел, буду очень рад комментариям и критике. Этот пост содержит самые базовые вещи, которые надо сделать сразу, что-бы избежать лишних проблем в дальнейшем.

В данный момент я использую Emacs 23.1.1 под Gentoo.

Если вы планируете использовать встроенный инструмент customize совместно с ручной настройкой, то рекомендую выделить для генерируемой им конфигурации отдельный файл.

~/.emacs:

;; Custom settings file
(setq custom-file "~/.emacs.d/custom.el")
(load custom-file)


Также вынесем в отдельный файл общие настройки, оставив для ~/.emacs роль управляющего файла.

~/.emacs:

;; General settings file
(load "~/.emacs.d/general.el")


Заставляем Emacs "общаться" с clipboard-ом X (это не нужно в MS Windows и Mac OS).

~/.emacs.d/general.el:

;; Interact with OS clipboard
(setq x-select-enable-clipboard t)


Убираем Toolbar и Scrollbar. Это конечно по желанию, но по моему они мешают основной идее Emacs.

~/.emacs.d/general.el:

;; Turn off scrollbar, toolbar and menubar
(scroll-bar-mode nil)
(tool-bar-mode nil)
(menu-bar-mode nil)


Включаем отображение номера колонки поинта (курсора).

~/.emacs.d/general.el:

;; Turn on column number mode
(column-number-mode t)


Подсветка парной скобки.

~/.emacs.d/general.el:

;; Highlight brackets
(show-paren-mode t)


Замещаем выделенный текст любым вводом.

~/.emacs.d/general.el:

;; Delete selected text when typing
(delete-selection-mode t)


И устанавливаем шрифт по умолчанию.

~/.emacs.d/general.el:

;; Font
(set-default-font "Monospace-9")


Ну, вот, теперь можно двигаться дальше.

October 16, 2009

Pg_Migrator для 8.4 готов, новое видео

Перевод Pg_Migrator Done for 8.4, New Video с Bruce Momjian Postgres Blog

Последний релиз pg_migrator состоялся более двух месяцев назад. С тех пор я не получил ни одного отчёта об ошибках, более того, было несколько сообщений об успешных миграциях. По этой причине, беру на себя ответственность объявить разработку pg_migrator завершенной и приостановленной до того, как релиз 8.5 будет на подходе.

Также, EnterpriseDB выпустила вводное видео, где я рассказываю о pg_migrator.

July 2, 2009

Итак, вышел PostgreSQL 8.4

«1 июля 2009 — Всемирная группа разработчиков PostgreSQL выпустила новую версию PostgreSQL, продолжая активную разработку самой развитой системы управления базами данных с открытым исходным кодом. Новая версия содержит множество улучшений, делающих администрирование, написание запросов и программирование баз данных PostgreSQL более простым, чем когда-либо. Благодаря 293 новым функциям и улучшениям, содержащимся в версии 8.4, причин выбрать PostgreSQL для вашего нового проекта стало ещё больше.»

Более подробно тут http://postgresmen.ru/articles/view/151

p.s. Я скоро вернусь ;)

March 14, 2009

В ожидании 8.4 - pg_stat_statements

Перевод Waiting for 8.4 - pg_stat_statements с select * from depesz;

4 января Tom Lane применил патч от Takahiro Itagaki, добавляющий новый contrib модуль - pg_stat_statement:

Добавляет contrib/pg_stat_statements для сбора статистики выполнения запросов в рамках всего сервера.

Takahiro Itagaki

Для чего же это? На самом деле это поможет избавиться от некоторых трудностей таким проектам как pgFoouine или мой analyze.pgsql.logs.pl.

В данный момент, если вы хотите увидеть статистику запросов, вам надо логировать их, а затем использовать какое-либо ПО, которое разберёт лог, нормализует запросы и сформирует по ним сводные данные.

Теперь же часть с разбором лога больше не требуется [*].

Вот как это работает.

Во первых, вам потребуется изменить ваш postgresql.conf. Откройте его и найдите параметр shared_preload_libraries. Добавьте туда pg_stat_statements, следующим образом:

shared_preload_libraries = 'pg_stat_statements' # (change requires restart)

Как видно из комментария, изменения требуют перезапуска сервера. Но, перед этим добавим в .conf файл ещё несколько опций:

pg_stat_statements.max = 100
pg_stat_statements.track = top
pg_stat_statements.save = off

Для того чтобы это заработало нам надо добавить "pg_stat_statement" в опцию "custom_variable_classes", которая обычно пустая, но если она у вас уже определена, то просто дополните её вот так:

custom_variable_classes = 'depesz,pg_stat_statements' # list of custom variable class names

Затем можно перезапустить PostgreSQL..

Теперь отслеживание запросов включено, но для просмотра статистики нужно создать соответствующие функции и вью, выполнив pg_stat_statements.sql на любой базе данных:

# \i work/share/postgresql/contrib/pg_stat_statements.sql
SET
CREATE FUNCTION
CREATE FUNCTION
CREATE VIEW
GRANT
REVOKE

(конечно же путь моет быть другим).

Что же, посмотрим как это работает. Первым делом проверим (сразу после коннекта) пустую статистику:

# select * from pg_stat_statements;
userid | dbid | query | calls | total_time | rows
--------+------+-------+-------+------------+------
(0 rows)

И повторим последний запрос:

# select * from pg_stat_statements;
userid | dbid | query | calls | total_time | rows
--------+-------+-----------------------------------+-------+------------+------
10 | 16389 | select * from pg_stat_statements; | 1 | 0.000131 | 0
(1 row)

Вау! Работает.

Теперь очистим статистику (select pg_stat_statements_reset();) и выполним несколько тестов:

(pgdba@[local]:5840) 15:42:41 [pgdba]
# select 1 + 2;
?column?
———-
3
(1 row)

(depesz@[local]:5840) 15:40:39 [depesz]
# select 2 + 3;
?column?
———-
5
(1 row)

(depesz@[local]:5840) 15:43:13 [depesz]
# select count(*) from pg_class where relkind = ‘r’;
count
——-
50
(1 row)

Как же теперь выглядит наша статистика?

# select * from pg_stat_statements;
userid | dbid | query | calls | total_time | rows
--------+-------+----------------------------------------------------+-------+------------+------
16384 | 16388 | select count(*) from pg_class where relkind = 'r'; | 1 | 0.000271 | 1
10 | 16389 | select 1 + 2; | 1 | 1.9e-05 | 1
16384 | 16388 | select 2 + 3; | 1 | 2.2e-05 | 1
10 | 16389 | select pg_stat_statements_reset(); | 1 | 3.3e-05 | 1
(4 rows)

Здорово. И как это будет работать с prepared statements?

# select pg_stat_statements_reset();
pg_stat_statements_reset
--------------------------

(1 row)

# prepare x(int4, int4) as select $1 + $2;
PREPARE
# execute x(1,2);
?column?
----------
3
(1 row)

# execute x(2,3);
?column?
----------
5
(1 row)

(pgdba@[local]:5840) 15:45:54 [pgdba]
# prepare y(int4, int4) as select $1 + $2;
PREPARE

(pgdba@[local]:5840) 15:46:00 [pgdba]
# execute y(3,4);
?column?
———-
7
(1 row)

(pgdba@[local]:5840) 15:46:05 [pgdba]
# select * from pg_stat_statements;
userid | dbid | query | calls | total_time | rows
——–+——-+——————————————+——-+————+——
10 | 16389 | prepare y(int4, int4) as select $1 + $2; | 1 | 1.7e-05 | 1
10 | 16389 | select pg_stat_statements_reset(); | 1 | 3.4e-05 | 1
10 | 16389 | prepare x(int4, int4) as select $1 + $2; | 2 | 3.3e-05 | 2
(3 rows)

Интересно. Смотрится так как будто "prepare" был выполнен столько раз, сколько он был запущен. Не смотря на этот момент - выглядит хорошо.

И так, я настроил pg_stat_statements на хранение 100 различных запросов. Что же случится после сотого? Какой же будет уделён?

Эта простая команда добавит 100 разных запросов:

( echo "SELECT pg_stat_statements_reset();"; for a in $( seq 1 99 ); do echo "select $a;"; done ) | psql

# select count(*) from pg_stat_statements;
count
-------
100
(1 row)

Но "select count(*) from pg_stat_statements" будет также добавлен. Так что, что-то должно быть удалено. Или, может, count(*) не был добавлен к статистике? Давайте проверим:

# select * from pg_stat_statements order by query;
...

Вероятно, pg_stat_statements удаляет случайную запись с наименьшим количеством вызовов. Т.е. в ста записях вызванных по одному разу, мы не сможем найти ту, которая будет удалена, при появлении нового запроса. Но в общем, это не так уж и важно.

В заключении, я думаю, что польза от модуля будет намного больше, если он будет сохранять запросы без параметров (т.е. вместо "select 2 + 3" -> "select $1 + $2", как-то так), иначе, на реальных базах данных, буфер запросов будет заполняться слишком быстро, и не будет заметен факт того, что "select * from table where id = 3" и "select * from table where id = 23" практически одно и тоже [*].

Но, по крайней мере уже есть какой-то аналитический инструмент для небольших систем.

От автора перевода:

Вообще странно, по моему автор оригинала что-то путает, в документации по модулю всё выглядит намного лучше - факт того, что "select * from table where id = 3" и "select * from table where id = 23", будет учитываться, т.е. запросы нормализуются. Кроме того, автор почему-то не упомянул о такой важной вещи как "pg_stat_statements.track = all", отслеживании вложенных запросов, например, внутри функций.

UPD.
Я был не прав - Hubert описал всё верно, неточность в незаконченной документации к версии 8.4. Тут наш с ним небольшой диалог, где он представил объяснение и результаты тестов.

March 4, 2009

У блога появился чат-бокс

Теперь, благодаря www.hab.la, вы можете задать мне вопрос прямо на этом блоге и тут же получить от меня ответ. Ищите чат-бокс в правом нижнем углу страницы.