Трюки с SQL от DBA. Небанальные советы для разработчиков БД / Блог компании Group / Хабр

Содержание
  1. Инструменты для авторов решений на основе oracle
  2. Не планируйте начало длительных процессов на начало любого часа
  3. Введение
  4. Обновляйте лишь то, что нужно обновить
  5. Hora (keep tool)
  6. Orapowertools (dkg advanced solutions)
  7. Pl/sql developer (allround automation)
  8. Sql navigator (quest software)
  9. Toad (quest software)
  10. В колонках с низкой избирательностью избегайте индексов
  11. Возврат результатов из cte
  12. Всегда загружайте отсортированные данные
  13. Делайте индексы «невидимыми»
  14. Для промежуточных данных используйте unlogged-таблицы
  15. Индексное сканирование (index scan)
  16. Используйте частичные индексы
  17. Колонки с высокой корреляцией индексируйте с помощью brin
  18. Команда cluster
  19. Корреляция
  20. Обобщённые табличные выражения (cte)
  21. Оптимизируем pages_per_range
  22. Оценка размера индекса
  23. Пишем гаджет windows sidebar с нуля
  24. При больших загрузках отключайте ограничения и индексы
  25. Разбираемся с pages_per_range
  26. Реализуйте процессы целиком с помощью with и returning
  27. Сканирование по битовой карте (bitmap scan)
  28. Создаём brin
  29. Часть 1. инструменты для oracle
  30. Я админ базы данных приложения
  31. Заключение

Инструменты для авторов решений на основе oracle

К

Не планируйте начало длительных процессов на начало любого часа

Инвесторы знают, что могут происходить странные события, когда цена акций достигает красивых круглых значений, например, 10$, 100$, 1000$. Вот

[…] цена активов может непредсказуемо меняться, пересекая круглые значения вроде $50 или $100 за акцию. Многие неопытные трейдеры любят покупать или продавать активы, когда цена достигает круглых чисел, потому что им кажется, что это справедливые цены.

С этой точки зрения разработчики не слишком отличаются от инвесторов. Когда им нужно запланировать длительный процесс, они обычно выбирают какой-то час.

Типичная ночная нагрузка на систему.

Это может привести к всплескам нагрузки в эти часы. Так что если вам нужно запланировать длительный процесс, то больше шансов, что в другое время система будет простаивать.

Также рекомендуется применять в расписаниях случайные задержки, чтобы не запускаться каждый раз в одно и то же время. Тогда даже если на этот час запланирована другая задача, это не будет большой проблемой. Если вы применяете таймер systemd, можете воспользоваться опцией RandomizedDelaySec.

Введение

П

Сегодня мне хотелось бы рассмотреть еще одну категорию инструментов, считающихся
вспомогательными, но при этом широко применяющихся при разработке приложений
с базами данных, — утилиты, предназначенные для так называемой post-case-обработки
баз данных, то есть для разнообразных манипуляций с базой данных, которые выполняются
после ее проектирования в процессе разработки приложений.

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

Сейчас трудно найти СУБД, в комплект поставки которой не входят утилиты для
администрирования баз данных и простейших манипуляций, таких как создание таблиц,
ввод данных, создание серверного кода. Как минимум, приложение, позволяющее
создавать пустую базу данных, вводить и выполнять SQL-запросы, имеется в составе
почти любой серверной СУБД, а в большинстве случаев можно найти утилиты, предоставляющие
более удобный интерфейс для манипуляции метаданными и данными, нежели ввод SQL-запросов.

Правда, в ряде случаев административные утилиты могут включаться в наиболее
дорогие версии серверных СУБД и не входить в состав стандартных или персональных
версий. Вот тут-то и пригодятся продукты независимых производителей, способные
заменить административные утилиты и во многих случаях оказывающиеся гораздо
более удобными для разработчиков приложений.

Первая статья данного цикла будет посвящена инструментам, предназначенным для
разработчиков решений на основе СУБД Oracle. В последующих статьях мы обсудим
утилиты, полезные авторам приложений, использующих другие серверные СУБД.

Обновляйте лишь то, что нужно обновить

Операция

UPDATE

потребляет довольно много ресурсов. Для её ускорения лучше всего обновлять только то, что нужно обновить.

Вот пример запроса на нормализацию колонки email:

Hora (keep tool)

Hora (Handy Oracle Tool) представляет собой интегрированную среду для разработчиков
и администраторов и позволяет осуществлять все наиболее часто встречающиеся
операции. Данный продукт поддерживает отладку кода SQL и PL/SQL, генерацию отчетов,
импорт и экспорт данных.

Hora (Keep Tool)

В качестве дополнения к этому инструменту предусмотрено несколько вызываемых
из него утилит того же производителя для генерации диаграмм баз данных (ER Diagrammer),
документации в формате HTML (HTML Documentation Generator), инструменты для
обратного проектирования баз данных и редактирования скриптов, средства отладки
кода PL/SQL (PL/SQL Debugger).

ER Diagrammer (Keep Tool)

PL/SQL Debugger (Keep Tool)

Orapowertools (dkg advanced solutions)

OraPowerTools компании DKG Advanced Solutions представляет собой набор утилит
для разработчиков решений на основе Oracle и администраторов этой СУБД. Этот
набор содержит утилиты OraEdit PRO — среду разработки баз данных и кода PL/SQL,
DBDiff for Oracle — утилиту сравнения двух баз данных (в том числе управляемых
разными версиями сервера) и создания обновлений на основе найденных различий
и утилиту DBScripter for Oracle, позволяющую создавать скрипты для генерации
баз данных и заполнения их данными. Все эти утилиты доступны и по отдельности.

DBDiff for Oracle (DKG Advanced Solutions)

OraEdit PRO (DKG Advanced Solutions)

Помимо указанных утилит, разработчикам доступна и бесплатная утилита OraEdit
того же производителя.

Pl/sql developer (allround automation)

PL/SQL Developer, отличающийся относительно невысокой ценой, представляет собой
среду разработки для авторов кода PL/SQL. В отличие от рассмотренных выше продуктов,
он не содержит большого количества инструментов администрирования. PL/SQL Developer
предназначен главным образом для разработчиков, и в этом плане данный инструмент
оказывается весьма привлекательным — в его составе есть средства автоматического
завершения кода, инструменты для создания шаблонов кода, графический интерфейс
к отладчику и профилировщику Oracle, инструмент для графического построения
запросов. В этот продукт удачно интегрирована документация Oracle.

PL/SQL Developer (Allround Automation)

Sql navigator (quest software)

SQL Navigator for Oracle 4.5 — весьма удобный инструмент для визуального редактирования
данных и метаданных, генерации скриптов (в том числе и скриптов для заполнения
таблиц данными). Этот инструмент содержит средства синтаксического выделения
кода SQL и PL/SQL, инициирования компиляции кода, редактирования данных, экспорта
результатов запросов в различные форматы, поддерживает многие особенности Oracle
10g (новые ключевые слова, типы данных, отображение хранения базы данных на
нескольких дисках).

SQL Navigator (Quest Software)

Данный продукт позволяет значительно повысить продуктивность создания и тестирования
кода PL/SQL, осуществлять поиск объектов в базе данных, выполнять запросы в
отдельном потоке. Отметим, что этот продукт очень популярен среди разработчиков.

Гаджет:  Гаджеты Календари для Windows 7 скачать бесплатно » Страница 2

Toad (quest software)

Утилита TOAD (Tool for Oracle Application Developers) предназначена для разработчиков
и администраторов баз данных. Она предоставляет удобную среду создания кода
Oracle, использующую профилировщик и отладчик кода самой компании Oracle, позволяет
осуществлять мониторинг базы данных, управлять файлами, в том числе и с помощью
протокола FTP, уведомлять администратора базы данных о возникших проблемах,
осуществлять поиск нужного объекта в базе данных.

TOAD (Quest Software)

TOAD содержит три основных компонента: Database Browser, SQL Editor и PL/SQL
Procedure Editor, а также панель SQL Modeller, позволяющую отобразить структуру
базы данных в графическом виде. Для администраторов TOAD предоставляет удобный
графический пользовательский интерфейс ко многим утилитам командной строки самой
Oracle.

В колонках с низкой избирательностью избегайте индексов

Допустим, у вас есть процесс регистрации, при котором пользователь входит по адресу почты. Чтобы активировать аккаунт, нужно верифицировать почту. Таблица может выглядеть так:

Возврат результатов из cte

Одно из преимуществ исполнения DML внутри выражения

WITH

заключается в том, что вы можете вернуть из него данные с помощью ключевого слова

. Допустим, нам нужен отчёт о количестве обновлённых и удалённых строк:

Всегда загружайте отсортированные данные


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

Допустим, у вас есть огромная таблица с конкретными продажами:

Делайте индексы «невидимыми»

В PostgreSQL есть классная фича

. За годы работы с Oracle я привык в конце транзакций использовать такие DDL-команды, как

CREATEDROPALTER

. Но в PostgreSQL выполнять DDL-команды можно внутри транзакции, а изменения будут применены только после коммита транзакции.

Недавно я обнаружил, что использование транзакционного DDL может сделать индексы невидимыми! Это полезно, когда хочется увидеть план исполнения без индексов.

Например, в таблице sale_fact мы создали индекс по колонке sold_at. План исполнения запроса на извлечение июльских продаж выглядит так:

db=# EXPLAIN
db-# SELECT *
db-# FROM sale_fact
db-# WHERE sold_at BETWEEN '2020-07-01' AND '2020-07-31';
                                         QUERY PLAN
--------------------------------------------------------------------------------------------
 Index Scan using sale_fact_sold_at_ix on sale_fact  (cost=0.42..182.80 rows=4319 width=41)
   Index Cond: ((sold_at >= '2020-07-01'::date) AND (sold_at <= '2020-07-31'::date))P

Чтобы увидеть, как выглядел бы план, если бы индекса

sale_fact_sold_at_ix

не было, можно поместить индекс внутрь транзакции и немедленно откатиться:

db=# BEGIN;
BEGIN

db=# DROP INDEX sale_fact_sold_at_ix;
DROP INDEX

db=# EXPLAIN
db-# SELECT *
db-# FROM sale_fact
db-# WHERE sold_at BETWEEN '2020-07-01' AND '2020-07-31';
                                   QUERY PLAN
---------------------------------------------------------------------------------

 Seq Scan on sale_fact  (cost=0.00..2435.00 rows=4319 width=41)
   Filter: ((sold_at >= '2020-07-01'::date) AND (sold_at <= '2020-07-31'::date))

db=# ROLLBACK;
ROLLBACK


Сначала начнём транзакцию с помощью

BEGIN

. Затем дропнем индекс и сгенерируем план исполнения. Обратите внимание, что план теперь использует полное сканирование таблицы, словно индекса не существует. В этот момент транзакция всё ещё выполняется, поэтому индекс пока не дропнут. Для завершения транзакции без дропа индекса откатим её с помощью команды

ROLLBACK

Проверим, что индекс ещё существует:

db=# di  sale_fact_sold_at_ix
                                 List of relations
 Schema |         Name         | Type  | Owner |   Table   |  Size
-------- ---------------------- ------- ------- ----------- ---------
 public | sale_fact_sold_at_ix | index | haki  | sale_fact | 2224 kB

Другие базы, которые не поддерживают транзакционный DDL, позволяют достичь цели иначе. Например, Oracle позволяет вам пометить индекс как

, и тогда оптимизатор будет его игнорировать.

Внимание: если дропнуть индекс внутри транзакции, это приведёт к блокировке конкурентных операций SELECT, INSERT, UPDATE и DELETE в таблице, пока транзакция будет активна. Осторожно применяйте в тестовых средах и избегайте применения в эксплуатационных базах.

Для промежуточных данных используйте unlogged-таблицы

Когда вы меняете данные в PostgreSQL, изменения записываются в журнал с упреждающей записью (

). Он используется для поддержания целостности, быстрой переиндексации в ходе восстановления и поддержки репликации.

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

Промежуточными называют одноразовые таблицы, в которых хранятся временные данные, используемые для реализации каких-то процессов. К примеру, в ETL-процессах очень часто загружают данные из CSV-файлов в промежуточные таблицы, очищают информацию, а затем грузят её в целевую таблицу. В таком сценарии промежуточная таблица — одноразовая и не используется в резервных копиях или репликах.

UNLOGGED-таблица.

Промежуточные таблицы, которые не нужно восстанавливать в случае сбоя и которые не нужны в репликах, можно задать как UNLOGGED:

CREATE UNLOGGED TABLE staging_table ( /* table definition */ );

Внимание

: прежде чем использовать

UNLOGGED

, убедитесь, что полностью понимаете все последствия.

Индексное сканирование (index scan)


Внесём небольшое изменение в загрузку данных.

Используйте частичные индексы

В предыдущей главе мы создали индекс для колонки с булевыми значениями, в которой около 90 % записей были

true

(активированные пользователи).

Когда мы запросили количество активных пользователей, база не использовала индекс. А когда запросили количество неактивированных, база использовала индекс.

Возникает вопрос: если база не собирается пользоваться индексом для отфильтровывания активных пользователей, зачем нам индексировать их в первую очередь?

Прежде чем ответить на это вопрос, давайте посмотрим на вес полного индекса по колонке activated:

Колонки с высокой корреляцией индексируйте с помощью brin

Когда речь заходит об индексах, многие разработчики думают о В-деревьях. Но PostgreSQL предлагает и другие типы индексов, например,

BRIN спроектирован для работы с очень большими таблицами, в которых некоторые колонки обладают естественной корреляцией со своим физическим местоположением внутри таблицы

Команда cluster

Другой способ «сортировки таблицы на диске» по конкретному индексу заключается в использовании команды

Например:

Корреляция

Когда база анализирует таблицу, она собирает всю возможную статистику. Одним из параметров является

Статистическая корреляция между физическим порядком строк и логическим порядком значений в колонках. Если значение около -1 или 1, индексное сканирование по колонке считается выгоднее, чем когда значение корреляции около 0, поскольку снижается количество случайных обращений к диску.

Как объясняется в официальной документации, корреляция является мерой того, как «отсортированы» значения в конкретной колонке на диске.

Корреляция = 1.

Если корреляция равна 1 или около того, это означает, что страницы хранятся на диске примерно в том же порядке, что и строки в таблице. Такое встречается очень часто. Например, у автоинкрементирующихся ID корреляция обычно близка к 1. У колонок с датами и временными метками, которые показывают, когда были созданы строки, корреляция тоже близка к 1.

Гаджет:  гаджеты металл — купите гаджеты металл с бесплатной доставкой на АлиЭкспресс version

Если корреляция равна -1, страницы отсортированы в обратном порядке относительно колонок.

Корреляция ~ 0.

Если корреляция близка к 0, это означает, что значения в колонке не коррелируют или почти не коррелируют с порядком страниц в таблице.

Вернёмся к sale_fact. Когда мы загрузили данные в таблицу без предварительной сортировки, корреляции были такими:

Обобщённые табличные выражения (cte)

С помощью

, также известных как выражение

WITH

, мы можем выполнить всю процедуру с помощью единственного SQL-выражения:

Оптимизируем pages_per_range

Согласно плану исполнения, база убрала из страниц 23 130 строк, которые нашла с помощью индекса. Это может говорить о том, что заданный нами для индекса диапазон слишком велик для этого запроса. Создадим индекс с вдвое меньшим количеством страниц в диапазоне:

Оценка размера индекса

Другим важным преимуществом BRIN является его размер. В предыдущих главах мы для поля

sold_at

создали индекс на основе В-дерева. Его размер был 2 224 Кб. А размер BRIN с параметром

pages_per_range=128

всего 48 Кб: в 46 раз меньше.

Schema |         Name          | Type  | Owner |   Table   | Size
-------- ----------------------- ------- ------- ----------- -------
 public | sale_fact_sold_at_bix | index | haki  | sale_fact | 48 kB
 public | sale_fact_sold_at_ix  | index | haki  | sale_fact | 2224 kB


На размер BRIN также влияет

pages_per_range

. К примеру, BRIN с

pages_per_range=2

весит 56 Кб, чуть больше 48 Кб.

Пишем гаджет windows sidebar с нуля

Недавно мне понадобилось создать гаджет для Windows Sidebar. Навыков в этом у меня не было, поэтому, немного погуглив и почитав

документацию

, приступаем.

Сразу покажу то, что получилось в итоге
Трюки с SQL от DBA. Небанальные советы для разработчиков БД / Блог компании  Group / Хабр

Гаджет будет получать информацию с сайта в виде xml, парсить и, собственно, отображать. Также гаджет будет проверять наличие новых версий, и в случае их присутствия, отказываться работать 🙂
Изначально, ради получения опыта, хотел написать гаджет полностью на VBScript (так как с ним еще не имел дела), но в конечном итоге пришлось делать вставки на JavaScript.
Перейдем непосредственно к коду. Весь код здесь я рассматривать не буду, покажу лишь основные моменты. Ссылка на готовый гаджет – в конце статьи.
Главный файл гаджета – его манифест – файл Gadget.xml. Он должен называться именно так и располагаться в корне нашего архива (гаджет есть ни что иное, как архив ZIP с расширением .gadget).

<?xml version="1.0" encoding="utf-8" ?>
<gadget>
 <name>Weather from Info.Denms.Ru</name>
 <version>1.0.1232</version>
 <hosts>
  <host name="wdenms">
   <base type="HTML" apiVersion="1.0.0" src="main.html" />
   <permissions>Full</permissions>
   <platform minPlatformVersion="1.0" />
  </host>
 </hosts>
  <icons>
    <icon width="64" height="64" src="icon.png" />
  </icons> 
 <author name="cvs">
  <info url="http://info.denms.ru" />
 </author>
 <description>Weather Widget (Info.Denms.Ru)</description>
</gadget>

Рассмотрим его более подробно.
Элемент <base> должен содержать apiVersion, равный 1.0.0 (на данный момент), а также атрибут src, в котором указан главный файл нашего гаджета;
<permissions> — разрешения для гаджета. Устанавливаем равным full;
<platform> — минимальная версия Widows Sidebar. На данный момент – 1.0;
Параметры <name> — имя гаджета, <version> — версия, <author> — информация об авторе, <info> — ссылка на страницу с гаджетом, <icon> — иконка гаджета и <descrtiption> будут отображаться на панели установленных гаджетов.

Файл main.html – обычный html файл, приводить его полностью не буду, остановлюсь лишь на некоторых моментах.
С помощью элемента g:background задается фон гаджета. Сделаем его прозрачным.

<g:background id="background" style="position:absolute; z-index:-1; top:0; left:0;" opacity="0"></g:background>

Гаджет может находиться в двух состояниях – docked (слева на скрине выше), и undocked (справа). Будем хранить текущее состояние гаджета в переменной JavaScript docked.

<SCRIPT Language="VBScript">
'Вызов функции JavaScript из области VBS
function isDocked
    isDocked = isDockedJS()
End Function    
</script>
<script src="main.vbs" type="text/vbscript"></script>

<SCRIPT Language="JavaScript">
    docked = 0;
    function isDockedJS() { 
      return docked;
    }
</SCRIPT>
<script type="text/javascript" src="main.js"></script>

Функция-обертка isDocked потребуется нам в дальнейшем, чтобы из VBScript узнать текущее состояние гаджета (как я не старался, но реализовать это на чистом VBScript не смог). Еще одно замечание – скрипты корректно работают именно в этом порядке, т.е. сначала описываем скрипты VBScript, потом JavaScript.

Остальные элементы в main.html представлены элементами DIV с абсолютным позицированием. Впоследствии из скриптов мы будем обращаться к ним по их id.

  <div id="small_needupdate"></div>

С помощью JavaScript зададим состояния docked и undocked для гаджета, а так же укажем файл настроек (main.js)

System.Gadget.onDock = resize;
System.Gadget.onUndock = resize;
System.Gadget.settingsUI = "settings.html";
System.Gadget.onSettingsClosed = SettingsClosed;

docked=0; //начальное состояние гаджета
resize(); //инициализация

Как видно из листинга выше, при смене состояний гаджета будет вызываться функция resize().

function resize() {

 bd = document.body.style;
 System.Gadget.beginTransition();

 if (System.Gadget.docked) {
   // small state
    bd.width=148;  //устанавливаем размеры гаджета
    bd.height=201;
    docked = 1;
    bd.background='url(images/gadget.png) no-repeat'; //устанавливаем фон
   //далее следует перенос значений из состояния undocked в docked и обнуление элементов для состояния undocked
    document.getElementById("small_needupdate").innerHTML = document.getElementById("big_needupdate").innerHTML;
   document.getElementById("big_needupdate").innerHTML = "";
   //...
} else {
    // big state
    bd.width=230;
    bd.height=160;
    bd.background='url(images/gadgeth.png) no-repeat';
    docked=0;
    //перенос значений из состояния docked в undocked и обнуление элементов для состояния docked
   document.getElementById("big_needupdate").innerHTML = document.getElementById("small_needupdate").innerHTML;
   document.getElementById("small_needupdate").innerHTML = "";
   //...
}
System.Gadget.endTransition(System.Gadget.TransitionType.morph,1);
}

Также можно описать функцию сохранения настроек. В моем гаджете их нет, но для примера покажу как это делается

function SettingsClosed(event) {
 if (event.closeAction == event.Action.commit) {
  //alert System.Gadget.Settings.readString('test');
 }
}

readString – читает ранее сохраненную строку, writeString, соответственно, записывает.
Методы System.Gadget.beginTransition(); и System.Gadget.endTransition(); нужны для “плавного» изменения размера гаджета. В Windows Seven они игнорируются, но я все же оставил их для обратной совместимости.

Как уже говорилось выше, сервер предоставляет нам информацию о погоде в формате xml.

<?xml version="1.0"?>
<all>
  <day id="today">
  <temp>1.7</temp>
  <cloudyim>41</cloudyim>
  <cloudy>пасмурно</cloudy>
  <air>снег</air>
  <humidity>87</humidity>
  <wind_direction>Ю-З</wind_direction>
  <wind_speed>5</wind_speed>
  <min>-3</min>
  <max>-1</max>
</day>
<day id="ПТ">
  <min>-1</min>
  <cloudyim>26</cloudyim>
  <max>1</max>
</day>
  <day id="СБ">
  <min>-9</min>
  <cloudyim>41</cloudyim>
  <max>0</max>
</day>
…
</all>

Скачивать и парсить xml будем на VBScript.

Sub DownloadXML2
    Set objXML = CreateObject("Microsoft.XmlHttp")
    objXML.Open "GET", "http://info.kovonet.ru/weather.xml", True
    objXML.OnReadyStateChange = GetRef("objXML_onreadystatechange")
    objXML.setRequestHeader "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT"
    objXML.Send
    iTimeoutID = window.SetTimeout("mySleep", 1000)
End Sub

Функция mySleep будет проверять наше соединение на таймаут.

Sub mySleep
  if bRespReceived = "false" then 'ответ еще не получен
    iTimeout = iTimeout   1
    if (iTimeout > 30) then  'таймаут
       timerFirstRun = window.SetTimeout("Update", 60000) 'попытка повторного обновления через минуту
    else 'таймаут еще не достигнут, продолжаем считать секунды
      iTimeoutID = window.SetTimeout("mySleep", 1000)
    end if
   end if
End Sub

В случае успешного скачивания objXML.readyState будет равен четырем, а статус (objXML.status) вернет значение 200.

Function objXML_onreadystatechange()
  If (objXML.readyState = 4) Then
    'msgbox objXML.statusText
    If (objXML.status = 200) Then
      bRespReceived=true
      SaveFile(objXML.responseText)
    else 
      timerFirstRun = window.SetTimeout("Update", 60000) 'попытка повторного обновления через минуту
    End If
  End If
End Function

В этом случае сохраняем файл во временную папку Windows

Function SaveFile(what)
  Set fso = CreateObject("Scripting.FileSystemObject")
  tempFolder = fso.GetSpecialFolder(2)
  filepath = tempFolder "weather.xml"
  Dim fso1, tf
  Set fso1 = CreateObject("Scripting.FileSystemObject")
  Set tf = fso1.CreateTextFile(filepath, True, True)  'rewrite, unicode
  tf.Write(what) 
  tf.Close
  ParseXML
End Function

и начинаем парсить файл.

Sub ParseXML
  Set fso = CreateObject("Scripting.FileSystemObject")
  tempFolder = fso.GetSpecialFolder(2)
  filepath = tempFolder "weather.xml"
  Set xmlDoc = CreateObject("Msxml2.DOMDocument") 
  xmlDoc.async="false"
  xmlDoc.load(filepath)
  'главная нода – в нашем случае <all>
  Set currNode = xmlDoc.documentElement
  'дни недели – <day>
  Set dayNode = currNode.firstChild
  While Not dayNode Is Nothing
    Set currNode = dayNode.firstChild
    While Not currNode Is Nothing
      if currNode.parentNode.getAttribute("id") = "today" then 'сегодняшний день
      if currNode.nodeName = "temp" then document.getElementById(prefix "maintemp").innerHTML = currNode.childNodes(0).text Chr(176)
      'отображаем остальные элементы
    Else 'не сегодняшний день, отображаем более мелко
      '...
    end If
    Set currNode = currNode.nextSibling
    Wend
  Set dayNode = dayNode.nextSibling
Wend
End Sub

Проверка на новые версии производится точно таким же способом.
Не забываем создать файл настроек — settings.html, о существовании которого мы объявили выше.

<html>
 <head>
  <title>Настройки</title>
  <style type="text/css">
  body { width:220px; height:120px; }
  </style>
 </head>
 <body>
  <div style="text-align:center">
   <strong>Weather from Info.Denms.Ru<br/><script type="text/javascript">document.write(System.Gadget.version);</script></strong><br/>
   © cvs, 2021<br/>
   <a href="http://info.denms.ru">http://info.kovonet.ru</a><br/><br/>
  </div>
 </body>
</html>

Вот, собственно, и все. Буду рад, если моя (первая :)) статья оказалась кому-то полезной.

Гаджет:  Технологии, из-за которых вам стоит присмотреться к смартфонам OPPO - 4PDA

Использованные источники:
http://www.script-coding.com/XMLDOMscripts.html;
http://msdn.microsoft.com/en-us/library/bb508511(v=VS.85).aspx;
VBScript Programmers Reference, 3rd Edition;
ну, и, конечно, http://google.com.

Ссылка на гаджет – http://info.kovonet.ru/test.gadget.

При больших загрузках отключайте ограничения и индексы


Ограничения — важная часть реляционных баз данных: они сохраняют консистентность и надёжность данных. Но у всего своя цена, и чаще всего расплачиваться приходится при загрузке или обновлении большого количества строк.

Давайте зададим схему небольшого хранилища:

DROP TABLE IF EXISTS product CASCADE;
CREATE TABLE product (
    id serial PRIMARY KEY,
    name TEXT NOT NULL,
    price INT NOT NULL
);
INSERT INTO product (name, price)
    SELECT random()::text, (random() * 1000)::int
    FROM generate_series(0, 10000);

DROP TABLE IF EXISTS customer CASCADE;
CREATE TABLE customer (
    id serial PRIMARY KEY,
    name TEXT NOT NULL
);
INSERT INTO customer (name)
    SELECT random()::text
    FROM generate_series(0, 100000);

DROP TABLE IF EXISTS sale;
CREATE TABLE sale (
    id serial PRIMARY KEY,
    created timestamptz NOT NULL,
    product_id int NOT NULL,
    customer_id int NOT NULL
);

Здесь определяются разные типы ограничений, таких как «not null», а также уникальные ограничения…

Чтобы задать исходную точку, начнём добавлять в таблицу sale внешние ключи

db=# ALTER TABLE sale ADD CONSTRAINT sale_product_fk
db-# FOREIGN KEY (product_id) REFERENCES product(id);
ALTER TABLE
Time: 18.413 ms

db=# ALTER TABLE sale ADD CONSTRAINT sale_customer_fk
db-# FOREIGN KEY (customer_id) REFERENCES customer(id);
ALTER TABLE
Time: 5.464 ms

db=# CREATE INDEX sale_created_ix ON sale(created);
CREATE INDEX
Time: 12.605 ms

db=# INSERT INTO SALE (created, product_id, customer_id)
db-# SELECT
db-#    now() - interval '1 hour' * random() * 1000,
db-#    (random() * 10000)::int   1,
db-#    (random() * 100000)::int   1
db-# FROM generate_series(1, 1000000);
INSERT 0 1000000
Time: 15410.234 ms (00:15.410)


После определения ограничений и индексов загрузка в таблицу миллиона строк заняла около 15,4 с.

Теперь сначала загрузим данные в таблицу, и только потом добавим ограничения и индексы:

db=# INSERT INTO SALE (created, product_id, customer_id)
db-# SELECT
db-#    now() - interval '1 hour' * random() * 1000,
db-#    (random() * 10000)::int   1,
db-#    (random() * 100000)::int   1
db-# FROM generate_series(1, 1000000);
INSERT 0 1000000
Time: 2277.824 ms (00:02.278)

db=# ALTER TABLE sale ADD CONSTRAINT sale_product_fk
db-# FOREIGN KEY (product_id) REFERENCES product(id);
ALTER TABLE
Time: 169.193 ms

db=# ALTER TABLE sale ADD CONSTRAINT sale_customer_fk
db-# FOREIGN KEY (customer_id) REFERENCES customer(id);
ALTER TABLE
Time: 185.633 ms

db=# CREATE INDEX sale_created_ix ON sale(created);
CREATE INDEX
Time: 484.244 ms

Загрузка прошла гораздо быстрее, 2,27 с. вместо 15,4. Индексы и ограничения создавались после загрузки данных заметно дольше, но весь процесс оказался намного быстрее: 3,1 с. вместо 15,4.

К сожалению, в PostgreSQL с индексами так же поступить не получится, можно лишь выбрасывать и пересоздавать их. В других базах, например, Oracle, можно отключать и включать индексы без пересоздания.

Разбираемся с pages_per_range

Количество смежных страниц определяется параметром

pages_per_range

. Количество страниц в диапазоне влияет на размер и точность BRIN:


По умолчанию значение

pages_per_range

равно 128.

BRIN с более низким значением pages_per_range.

Для иллюстрации создадим BRIN с диапазонами по две страницы и поищем значение 5:

При двухстраничном диапазоне мы можем ограничить зону поиска блоками 5 и 6. Если диапазон будет трёхстраничным, индекс ограничит зону поиска блоками 4, 5 и 6.

Другим различием между двумя индексами является то, что когда диапазон равнялся трём страницам, нам нужно было хранить три диапазона, а при двух страницах в диапазоне мы получаем уже пять диапазонов и индекс увеличивается.

Реализуйте процессы целиком с помощью with и returning

Допустим, у вас таблица пользователей, и вы обнаружили, что в ней есть дублирующиеся данные:

Сканирование по битовой карте (bitmap scan)

В плане исполнения мы видим, что база использовала сканирование по битовой карте. Оно проходит в два этапа:


Страницы могут содержать много строк. На первом этапе индекс используется для поиска

страниц

. На втором этапе ищутся

строки

в страницах, отсюда следует операция

Recheck Cond

в плане исполнения.

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

Создаём brin

Возьмём таблицу

sales_fact

и создадим BRIN по колонке

sold_at

db=# CREATE INDEX sale_fact_sold_at_bix ON sale_fact
db-# USING BRIN(sold_at) WITH (pages_per_range = 128);
CREATE INDEX

По умолчанию значение

pages_per_range = 128

Теперь запросим период дат продаж:

Часть 1. инструменты для oracle

Введение

Инструменты для авторов решений на основе Oracle

   SQL Navigator (Quest Software)

   TOAD (Quest Software)

   Hora (Keep Tool)

   PL/SQL Developer (Allround Automation)

   OraPowerTools (DKG Advanced Solutions)

Заключение

Я админ базы данных приложения

У меня никогда не было желания возиться с бэкапами или настраивать хранилище (уверен, это увлекательно!). По сей день мне нравится говорить, что я админ БД, который знает, как разрабатывать приложения, а не разработчик, который разбирается в базах данных.

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

Содержание:

Заключение

В

В следующей статье данного цикла мы рассмотрим утилиты, предназначенные для
разработчиков решений на основе Microsoft SQL Server.

КомпьютерПресс 3’2005

Оцените статью
GadgetManiac
Добавить комментарий