четверг, 30 августа 2012 г.

iTextSharp. Как же с ним работать?

Недавно перед мной встала задача - генерировать на лету pdf документы. При использовании ключевых слов C# и PDF поисковые системы, как правило подсказывают, что нужно использовать библиотеку iTextSharp. У меня нет оснований не верить им, поэтому так и поступим.

После первого знакомства с возможностями библиотеки и примерами из сети объявились 4 неприятные новости.

  • iTextSharp это порт библиотеки iText, и никакие комментарии не приведены в соответствующий вид. Поэтому действовать приходится наощупь или заглядывать в код методов.
  • Раньше можно было генерировать файл из xml шаблона, который должен был соответствовать itext.dtd. Больше эта возможность не поддерживается.
  • В интернете много примеров кода с вызовом ITextHandler, в новых версиях такого класса в принципе нет. Поэтому половина сообщений на форумах по этой теме уже бесполезна.
  • Видимо сайт разработчика был переделан, поэтому многие ссылки, которые обещали нам решение приводят нас на главную страницу.
Так как же работать с этой библиотекой? Об этом, а так же о самых часто встречаемых трудностях и их решениях можно узнать под катом.

понедельник, 27 августа 2012 г.

Место есть?

Все знают как узнать сколько есть свободного места на ваших HDD. Но как узнать сколько свободного места в ваших файловых группах? Забиты они или же напротив лишь занимают место, а внутри очень мало данных? Ниже приведен скрипт для определения размера файлов, используемого и свободного объема в них, а так же размера, до которого будут расширяться файлы, когда места станет недостаточно.

select db_name(sa.dbid) as DBname 
 , sa.name as LogicalName
 , case sa.groupid
  WHEN 0 then 'LOG'
  ELSE sfg.groupname
   end as Filegroup
 , sa.filename as Filename
 , cast(sf.size*8/1024. as numeric(19,3))as sizeMB
 , cast(sf.spaceused*8/1024. as numeric(19,3)) as spaceusedMB
 , cast((sf.size-sf.spaceused)*8/1024. as numeric(19,3)) as freespaceMB
 , case sf.maxsize
  when -1 then 'Unlimited'
  else cast(cast(sf.maxsize*8/1024.  as numeric(19,3))as varchar(22))
   end as maxsizeMB
 , cast(sf.growth*8/1024. as numeric(19,3)) as nextgrowthMB
from master..sysaltfiles sa 
left join (
 select   cast(size as bigint) as size
   ,fileid
   ,groupid
   ,cast(fileproperty(name,'SpaceUsed')as bigint) as spaceused 
   ,cast(maxsize as bigint) as maxsize
   ,cast(case 
    when status & 0x100000 = 0 then growth
    else size*growth/100
    end as bigint) as growth
 from sysfiles
 ) sf on sf.fileid=sa.fileid 
  and sf.groupid = sa.groupid
left outer join sysfilegroups sfg on sfg.groupid = sf.groupid
where sa.dbid = db_id()
order by case when sa.groupid = 0 then 1 else 0 end, sa.groupid, sa.fileid

Владение этими данными очень важно для планирования и понимания внутренних процессов сервера. Ниже приведен пример возвращаемых данных. Видно, что в данном случае реальных данных в файлах очень мало.

четверг, 9 августа 2012 г.

Поиск неиспользуемых индексов

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

SELECT   
         OBJECT_SCHEMA_NAME(i.object_id)AS [Schema Name],
  OBJECT_NAME(i.object_id) AS [Table Name],
         i.name AS [Not Used Index Name],
         s.last_user_update AS [Last Update Time],
         s.user_updates AS [Updates]
FROM     sys.dm_db_index_usage_stats AS s
JOIN     sys.indexes AS i
ON       i.object_id = s.object_id
AND      i.index_id = s.index_id
JOIN     sys.objects AS o
ON       o.object_id = s.object_id
WHERE    s.database_id = DB_ID()
AND      (    user_scans   = 0
          AND user_seeks   = 0
          AND user_lookups = 0
          AND last_user_scan   IS NULL
          AND last_user_seek   IS NULL
          AND last_user_lookup IS NULL 
         )
AND      OBJECTPROPERTY(i.[object_id],         'IsSystemTable'   ) = 0
AND      INDEXPROPERTY (i.[object_id], i.name, 'IsAutoStatistics') = 0
AND      INDEXPROPERTY (i.[object_id], i.name, 'IsHypothetical'  ) = 0
AND      INDEXPROPERTY (i.[object_id], i.name, 'IsStatistics'    ) = 0
AND      INDEXPROPERTY (i.[object_id], i.name, 'IsFulltextKey'   ) = 0
AND      (i.index_id between 2 AND 250 OR (i.index_id=1 AND OBJECTPROPERTY(i.[object_id],'IsView')=1))
AND      o.type != 'IT'

--and OBJECT_SCHEMA_NAME(i.object_id) = 'Price'
ORDER BY 1,2,3

P.S. Прежде чем ринуться удалять индексы, ответьте себе на вопрос о том, как давно вы "чистили" статистику или перезагружали сервер? А все ли операции, запускаемые на вашем инстансе, были запущены после этого?