вторник, июля 31, 2007

Все забыл...

После 2 х лет программинга на .NET (c#, asp.net), MSSQL Server 2000 обнаружил что напрочь забыл foxpro, сегодня долго и мучительно вспоминал как создать таблицу и написать хранимую процедуру в fox 9-ке....

Потом мучился с oledb и обнаружил для себя что большая часть статементов и функций в провайдере не поддерживается :)

дождался :) анонса статьи на rsdn

Наша совместная с Михаилом статья проанонсирована на www.rsdn.ru:

Опыт практического применения t-sql в системах распределенных баз данных

нужно готовиться к отражению атак :-D

ps: полный текст статьи доступен в журнале rsdn #2-2007


понедельник, июля 30, 2007

Internal SQL Server error

В качестве последней задачи при работе с серверами ms sql 2000 пришлось менять структуры логов + нормализовать ранее ненормализованные данные, выделять отдельные словари, сложность была в том, что таблицы логов были огромны, данные, подлежащие нормализации и конвертации, как-то особенно ей не подвергались, ну и плюс наличие всякого рода мусора...ну да ладно, это вступление, суть не в этом, а в том, что после этой нормализации на нескольких серверах стала появляться ошибка:
Internal SQL Server error
причем на вставке только в одну и туже таблицу....лечили сначала перестройкой индексов, потом стали искать hotfix, нашли...

Cumulative list of the hotfixes that are available for SQL Server 2000 SP4

там же и описание нашей проблемы:

915436 (http://support.microsoft.com/kb/915436/) FIX: Error message when you run a complex insert query or a stored procedure in SQL Server 2000: "Internal SQL Server error"


сам hotfix выложен 19 июля 2007 года, для скачивания пока не доступен, а может просто не искали, так как решение проблемы нашлось само собой - читать дальше:

Hotfix information

A supported hotfix is now available from Microsoft, but it is only intended to correct the problem that is described in this article. Only apply it to systems that are experiencing this specific problem. This hotfix may receive additional testing. Therefore, if you are not severely affected by this problem, we recommend that you wait for the next SQL Server 2000 service pack that contains this hotfix.

To resolve this problem immediately, contact Microsoft Product Support Services to obtain the hotfix. For a complete list of Microsoft Product Support Services telephone numbers and information about support costs, visit the following Microsoft Web site:

Из описания проблемы обратил внимание на следующее:

SYMPTOMS

When you run a query or a stored procedure in SQL Server 2000, you may receive an error message that resembles the following:
Server: Msg 8624, Level 16, State 1, Line 1 Internal SQL Server error
This problem occurs when you use a complex insert query that joins several tables. Typically, this problem occurs when the query runs parallel across multiple processors.

When this problem occurs, you may also experience the following symptoms:
The query does not run.
You cannot see the SHOWPLAN_ALL or SHOWPLAN_TEXT output for the query.
Note State 1 and Line 1 in the error message help distinguish this problem from other types of 8624 error messages. If a different state and line number exist in the error message, you are probably not experiencing this problem.

Решил проверить...выдрал тот запрос, на котором собственно и происходила указанная ошибка, решил посмотреть план....
запрос типа

insert into
select

на сам select план получил, решил посмотреть план с учетом insert statement, и...реально увидел сообщение об ошибке....из описания симптомов обратил внимание также на следующее:


This problem occurs when you use a complex insert query that joins several tables. Typically, this problem occurs when the query runs parallel across multiple processors.

Это как раз наш случай, вышеуказанный запрос выполнялся на многопроцессорной машине, при работе c sql server были задействованы все имеющиеся 4ре процессора:


Image Hosted by ImageShack.us

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

option (maxdop 1), т.е. просто указав, что для моей вставки будет использоваться ресурсы только одного процессора...


т.е.

insert into

select <....>

option (maxdop 1)

посмотрим план, и...ошибка исчезла...





ps: вообщем, для моего случая это стало решением...не знаю, может кому и пригодится, благодарности принимаются в виде пива:)

Осталось 2 дня


оху...удивился утром...не забыть поздравить

пятница, июля 27, 2007

сегодня ж пятница :)

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

Microsoft SQL Web Data Administrator

В поисках sdk или какой-либо справки по написанию addins for management studio, о чем, собственно говоря, писал еще вчера, наткнулся еще на одну тулзу от microsoft под названием Microsoft SQL Web Data Administrator,
краткий обзор которой и представляю...

устанавливается она как asp.net web приложение по локальный iis, после чего доступна через http:\\localhost\webadmin - вы же конечно можете выставить данный сайт в инет для использования ее как средства удаленного администрирования ваших серверов...

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


вторая страница предлагает выбрать из списка баз данных интересующию



поработать с ее свойствами:



выполнить sql-скрипт в контексте текущей базы:



посмотреть полученный результат:



поработать с secutity:



выбрать и отредактировать код хранимой процедуры:





аналогично с любыми другими объектами базы данных, например, изменить структуру таблицы:





вообщем, убив полчаса на просмотр данного инструмента я бы :) НЕ рекомендовал ее вообще в качестве инструмента для администрирования вашего сервера, если только у вас нет под рукой enterprise manager или management studio...задумался, а вообще, может ли возникнуть такая ситуация, когда есть необходимость чтото подправить удаленно, а у тебя под рукой только чистый голый инет ... а ведь может наверно, когда ты сидишь мило в интернет-кафе :-D и забыл логин/пароль от терминала, хотя что это за админ такой - его среда обитания - это серверная... :-D


ps: пожалел потраченного времени...

pps: вообще, каждый раз, рассматривая какой-то новый инструмент, ожидаешь чего-то нового, комфортного чтоли, и каждый раз такое разочарование, сколько всякого рода сред и утилит уже перелопатил, хватит не на один обзор (надо наверно как-нить подготовить), а лучше EM и QA наверно еще не придумано,или я болею просто, или чего-то недогоняю, но даже management studio по сравнению с тем же самым EM такая убогая, какая-то кривая, большая чтоли...

ppps: написал и еще раз убедился в необходимости писать дальше свой job activity monitor в возможностью одновременного управления сразу несколькими серверами...




четверг, июля 26, 2007

SQL Server 2005 Best Practices Analyzer (July 2007)

Полдня потратил на поиски sdk для разработки add-on компонентов для ms sql management studio, решил порыться в дАунлоадах на microsoft, не нашел :).

Однако, наткнулся на забавную вешицу под названием SQL Server 2005 Best Practices Analyzer (July 2007). Суть работы данной утилитки в том, что бы просканировать указанный сервер, указав, что именно нужно просканировать, database engine, analisys services | integration services и выдать рекомендации, которые считаются правильными с точки зрения microsoft...Обычно такие вещи стараюсь отслеживать лично, но вот что выдал в качестве результатов на локальном моем драфтовом сервере этот аналайзер, и в принципе не могу не согласиться что рекомендации он выдает правильные....
gui построен в стиле IUI, что не мешало мне пару раз заблудиться, но в общем ui оказался очень даже ничего...

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


результаты сканирования:


report_issue_01


вообщем, рекомендую к просмотру :)

ps: sdk к концу дня так и не нашел, буду искать в другом месте:)

среда, июля 25, 2007

sysfiles и файлы базы данных

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

сам скрипт:



if isnull(object_id('tempdb..#files_info'), 0) > 0
drop table #files_info

create table #files_info ( database_name varchar(100) null default (db_name()),
critery int,
disk_letter varchar(10) null,
device varchar(10) null,
growth_expression varchar(100) null,
data_size_expression varchar(100) null,
data_size int null,
logic_file_name varchar(100) null,
filename varchar(100) null,
free_disk_space varchar(100) null default('')
)

declare @databases cursor ,
@d_name varchar(100),
@sql_script nvarchar(4000)

set @databases= cursor local forward_only for
select name
from master..sysdatabases
where sid <> 0x01


open @databases
fetch next from @databases into @d_name

while (@@fetch_status = 0 )
begin
set @sql_script =
'
insert into #files_info
select ''' + @d_name + ''' database_name, *
from (
select 0 critery,
substring(filename, 0, 3) disk_letter,
case
when (status & 0x40) = 0 then ''data file''
else ''log file''
end device,
case
when (status & 1048576) = 0 then cast( (growth * 8 /1024) as varchar(10)) + '' Mb ''
else cast(growth as varchar(10)) + '' % ''
end growth_expression,
''~'' + cast((size * 8 / 1024) as varchar(10)) + '' Mb '' data_size_expression,
(size * 8 / 1024) data_size,
name logic_file_name,
filename,
'''' free_disk_space
from ' + @d_name + '..sysfiles (nolock)
union
select 1 critery,
substring(filename, 0, 3) disk_letter,
'''' device,
'''' growth_expression,
''~'' + cast((sum(size) * 8 / 1024 /1024) as varchar(10)) + '' Gb '' data_size_expression,
(sum(size) * 8 / 1024) data_size,
'''' logic_file_name,
'''' filename,
'''' free_disk_space
from ' + @d_name + '..sysfiles (nolock)
group by substring(filename, 0, 3)
union
select 2 critery,
''total:'' disk_letter,
'''' device,
'''' growth_expression,
''~'' + cast((sum(size) * 8 / 1024 /1024) as varchar(10)) + '' Gb '' data_size_expression,
(sum(size) * 8 / 1024 ) data_size,
'''' logic_file_name,
'''' filename,
'''' free_disk_space
from ' + @d_name + '..sysfiles (nolock)
) innerselect
order by critery, disk_letter, device


'
execute sp_executesql @sql_script

fetch next from @databases into @d_name
end

-- свободное место на дисках
declare @disk_letters cursor,
@disk_letter varchar(10)

set @disk_letters = cursor local forward_only for
select distinct disk_letter
from #files_info
where critery = '1'
open @disk_letters
fetch next from @disk_letters into @disk_letter

while (@@fetch_status = 0)
begin
create table #output (text nvarchar(1000))


set @sql_script = '
execute master..xp_cmdshell ''dir ' + @disk_letter + ' /A:D ''
'
insert into #output
execute sp_executesql @sql_script

declare @free_text varchar(100)
set @free_text = ''

select top 1 @free_text = text
from #output
where text like '%bytes free%'
drop table #output

update #files_info
set free_disk_space = @free_text
where critery = 1
and disk_letter = @disk_letter

fetch next from @disk_letters into @disk_letter
end

close @disk_letters
deallocate @disk_letters

select '" + name + @"' connection_string_name, *
from #files_info
union all
select '" + name + @"' connection_string_name,
'all databases' database_name,
3 critery,
'total:' disk_letter,
'' device,
'' growth_expression,
'~' + cast(sum(data_size) as varchar(10)) + ' Gb ' data_size_expression,
sum(data_size) data_size,
'' logic_file_name,
'' filename,
'' free_disk_space
from #files_info
where critery = 2



результат приблизительно такой:



Одно неверное нажатие клавиши приводит иногда к печальным последствиям

за последние 2 года дважды наступаю на одни и те же грабли, когда доверяю не мозгу, а своей интуиции, и вообщем-то даже не обращаешь внимания на казалось бы выработанные безусловные рефлексы нажимать F5 для запуска какого-либо скрипта и одновременной проверки того, в какой ты базе этот скрипт запускаешь, на какой системе и прочее...
сегодня рефлексы не сработали, скрипт по перелопачиванию базы данных, который работал 2 дня, точнее результаты работы этого скрипта я убил ловким нажатием F5 на drop table, не там где нужно было :), потом долго тупил где же таблица...
выкурив пару сигарет, найденных в туалете, плюнув в унитаз, запустил работать заново, почесав репу, остановил скрипт, нашел баг, из-за чего же скрипт так долго работает, исправил его, запустил снова, жду .... надеюсь что часов за 10ть он перелопатит то что не мог сделать с моей медвежьей помощью пару дней...

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


вторник, июля 24, 2007

job activity monitor своими руками

это первый пост в моем блоге...не знаю, не хотелось вот так просто написать что-то вроде "тест", поэтому постараюсь написать чтонить полезное...на мой взгляд:)

по ходу своей деятельности в рамках работы приходится постоянно заниматься разработкой хранимых процедур для mssql 2000, написанием различного рода скриптов по обработке данных, и, что самое рутинное для меня, проверять работоспособность системы...точнее, систем, причем каждое утро, а по понедельникам и за последние дни, на что убивается уйма времени, сил и нервов...
как один из этапов проверки, что касается моего участка сбора данных, подготовки отчетов, трекинга, парсинга (красивое слово) заключается в проверке job-ов на куче серверов, т.е. нужно точно сказать, что такой-то job точно работает, такой то упал, причем если падал, то почему, по какой причине...
для этих целей обычно приходится запускать окно job activity monitor, причем для каждого инстанса ms sql server, итого в taskbar висит иногда порядка 15 окон...затем я смотрю, чтобы все job-ы работали - для этого просто обращаю внимание на поле status - но данное поле, даже если и говорит что successfull, не говорит мне о том, а были ли проблемы с рассматриваемым job-ом, поэтому приходится лезть дополнительно еще и в историю выполнения...еще + порядка 15 окон, и хорошо если нужно проверить один job на каждой системе, их тоже порядка 20-ти...надеюсь, представляете рутинность :)...
ну да ладно, солдаты трудностей не боятся, вроде как справлялся, но эти проверки надоели до боли в почках, поэтому решил облегчить себе задачу, запуская на каждой из систем следующий скрипт:





select isnull(SM.description, '') sysmessages_description,
case
when SJ.enabled = 1 then 'yes'
else 'no'
end enabled,
SJ.name,
SJH.step_id,
SJH.step_name,
SJH.sql_message_id,
SJH.sql_severity,
SJH.message,
case
when SJH.run_status = 0 then 'failed'
when SJH.run_status = 2 then 'retry'
when SJH.run_status = 3 then 'canceled'
when SJH.run_status = 3 then 'in progress'
else 'unknown'
end run_status,
cast(convert(varchar(10), SJH.run_date, 21) as datetime) run_date,
substring(str(1000000 + SJH.run_time, 7), 2, 6) run_time,
SJH.run_duration,
SJS.job_id, SJS.step_id, SJS.step_name, SJS.database_name,
cast(convert(varchar(10), SJS.last_run_date, 21) as datetime) last_run_date,
substring(str(1000000 + SJS.last_run_time, 7), 2, 6) last_run_time,
SJS.last_run_duration,
case
when run_date = last_run_date
and cast(convert(varchar(10), SJH.run_date, 21) as datetime) = cast(convert(varchar(10), getdate(), 21) as datetime) then 1
else 0
end alert_flag
from msdb..sysjobs SJ (nolock)
join msdb..sysjobsteps SJS (nolock) on SJS.job_id = SJ.job_id
join msdb..sysjobhistory SJH (nolock) on SJH.job_id = SJ.job_id and SJH.step_id = SJS.step_id
left join master..sysmessages SM (nolock) on SM.error = SJH.sql_message_id
where SJH.run_status <> 1
and SJS.last_run_date > replace(replace(replace(convert(varchar(10), dateadd(dd, -3, getdate()), 21), '-', ''), '/', ''), '.', '')
and SJH.run_date > replace(replace(replace(convert(varchar(10), dateadd(dd, -3, getdate()), 21), '-', ''), '/', ''), '.', '')
and SM.msglangid = 1033 -- <-- only 2005
order by SJH.run_date, SJ.name, SJS.step_id




идея такова, я хочу увидеть только список упавших по какой-либо причине job-ов, причем рассматриваю период два дня назад (прихожу в понеделник, хочу видеть что творилось в выходные) - для этого джойню sysjobs и sysjobhistory таблицы, причем только для того случая, где sysjobhistory.run_status <> 1 и только за последние два дня...в полученный рекордсет дополнительно вытаскиваю last_run_date самого job и его состояние в текущий момент, а также run_date упавших записей из истории...т.е., если run_date и last_run_date у меня равны и равны getdate(), то job продолжает падать до сих пор, если нет, его состояние нормализовалось, но вижу, что он падал в предыдущие два дня...(наверно, сумбурно получилось, но будет нагляднее на сриншоте, приложенном внизу)

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



В конфиге утилиты прописал connection strings ко всем серверам, указанный скрипт запускаю через sqlcommand ко всем серверам паралельно, тупо получаю datatables от каждой системы, мержу их в один и показываю в виде дерева через devexpress datagrid, красным подсвечиваю те записи, у которых last_run_date == run_date///

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

ps: в запросе был дополнительный join с sysmessages - объясню для чего... если в процессе работы job вываливалась куча ворнингов, скажем, на создание таблиц с длиной строки, прерышающей лимитное, sysjobhistory показывает все эти ворнинги вместо реального сообщения об ошибке, просто забивая и не оставляя места под последнее критическое сообщение...поэтому приходится брать sql_message_id (собственно id сообщения, которое было критическим в момент падения job) и вытаскивать по нему реальное сообщение об ошибке из sysmessages///

pps: по запросу программа высылается всем желающим, сейчас оформляю ее в нормальный gui, так что велкам...

ppps: мысль -> не реклама, а лень...двигатель прогресса