Оптимизация XML в C # - PullRequest
5 голосов
/ 21 мая 2009

Фон

У нас есть проект, который был запущен в .NET 1.1, перемещен в .NET 2.0, а недавно снова перемещен в .NET 3.5. Проект чрезвычайно ориентирован на данные и использует XML для многих своих файлов данных. Некоторые из этих XML-файлов довольно велики, и я хотел бы воспользоваться возможностью, чтобы в настоящее время улучшить взаимодействие приложения с ними. Если возможно, я хочу избегать постоянного хранения их в памяти, но, с другой стороны, я хочу ускорить доступ к их данным.

Текущая настройка использует XmlDocument и XPathDocument (в зависимости от того, когда и кем она была написана). Данные просматриваются при первом запросе и кэшируются во внутренней структуре данных (а не в виде XML, который в большинстве сценариев занимал бы больше памяти). В прошлом это была хорошая модель, поскольку у нее было быстрое время доступа и низкий объем памяти (или, по крайней мере, удовлетворительный объем памяти). Однако теперь есть функция, которая запрашивает большую часть информации за один раз, а не красиво распределенные запросы, которые у нас были ранее. Это приводит к тому, что загрузка, проверка и синтаксический анализ XML становятся видимым узким местом в производительности.

Вопрос

Учитывая большой файл XML, каков наиболее эффективный и отзывчивый способ запроса его содержимого (например, «существует ли элемент A с id = B?») Повторно без наличия XML в памяти?

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

Учитывая, что мы уже кешируем данные там, где можем, этот вопрос можно также прочитать как «который быстрее и использует меньше памяти; XmlDocument, XPathDocument синтаксический анализ на основе XmlReader или XDocument / LINQ-to-XML ? "

Редактировать: Еще проще, можем ли мы получить произвольный доступ к XML на диске без чтения всего файла сразу?

Пример

XML-файл содержит несколько записей:

<MyXml>
  <Record id='1'/>
  <Record id='2'/>
  <Record id='3'/>
</MyXml>

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

Цель

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

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


Обновление
Сегодня XMLTeam опубликовал блог , в котором содержатся отличные советы о том, когда использовать различные API-интерфейсы XML в .NET. Похоже, что-то на основе XmlReader и IEnumerable будет моим лучшим вариантом для сценария, который я привел здесь.

Ответы [ 6 ]

2 голосов
/ 23 мая 2009

Я недавно натолкнулся на этот технический документ, когда пытался выполнять потоковую передачу XML: Потоковая передача XML на основе API с мощными и функциональными обновлениями FLWOR Документ пытается работать с XML в памяти, но использует доступ LINQ .

Может быть, кому-то будет интересно.

2 голосов
/ 21 мая 2009

С XML я знаю только два пути

XMLReader -> поток больших данных XML в или используйте объектную модель XML DOM и считывайте весь XML сразу в память.

Если XML большой, у нас есть XML-файлы размером от 80 МБ и выше, чтение XML в память является ударом производительности. Нет реального способа «объединить» два способа работы с XML-документами. К сожалению.

1 голос
/ 21 мая 2009

Это может звучать глупо.
Но если у вас есть простые вещи для запроса, вы можете использовать регулярные выражения над файлами XML. (как они делают grep в Unix / Linux).

Прошу прощения, если это не имеет смысла.

0 голосов
/ 22 мая 2009

Просто мысль о комментариях JMarsch. Даже если процесс создания XML вашего процесса не подлежит обсуждению, рассматривали ли вы БД (или подмножество файлов XML, выступающих в качестве индексов) в качестве посредника? Очевидно, что это будет полезно только в том случае, если XML-файлы не обновляются более одного или двух раз в день. Полагаю, это необходимо сравнить с существующим механизмом кэширования.

Я не могу говорить со скоростью, но я предпочитаю XDocument / LINQ из-за синтаксиса.

Rich

0 голосов
/ 21 мая 2009

XmlReader будет использовать меньше памяти, чем XmlDocument, поскольку ему не нужно загружать весь XML в память за один раз.

0 голосов
/ 21 мая 2009

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

    public void ValidateXmlToXsd(string xsdFilePath, string xmlFilePath)
    {
        XmlSchema schema = ValidateXsd(xsdFilePath);
        XmlDocument xmlData = new XmlDocument();
        XmlReaderSettings validationSettings = new XmlReaderSettings();

        validationSettings.Schemas.Add(schema);
        validationSettings.Schemas.Compile();
        validationSettings.ValidationFlags = XmlSchemaValidationFlags.ProcessInlineSchema;
        validationSettings.ValidationType = ValidationType.Schema;
        validationSettings.ValidationEventHandler += new ValidationEventHandler(ValidationHandler);
        XmlReader xmlFile = XmlReader.Create(xmlFilePath, validationSettings);

        xmlData.Load(xmlFile);
        xmlFile.Close();
    }

    private XmlSchema ValidateXsd(string xsdFilePath)
    {
        StreamReader schemaFile = new StreamReader(xsdFilePath);
        XmlSchema schema = XmlSchema.Read(schemaFile, new ValidationEventHandler(ValidationHandler));
        schema.Compile(new ValidationEventHandler(ValidationHandler));
        schemaFile.Close();
        schemaFile.Dispose();

        return schema;
    }

    private void ValidationHandler(object sender, ValidationEventArgs e)
    {
        throw new XmlSchemaException(e.Message);
    }

Если xml не удается проверить, выдается XmlSchemaException.

Что касается LINQ, я лично предпочитаю использовать XDocument всякий раз, когда могу превышать XmlDocument. Ваша цель несколько субъективна, и, не зная точно, что вы делаете, я не могу сказать, идти этим путем или идти по этому пути с уверенностью, что это поможет вам. Вы можете использовать XPath с XDocument. Я должен сказать, что вы должны использовать то, что подходит вам лучше всего. Там нет проблем с использованием XPath иногда и LINQ в других случаях. Это действительно зависит от вашего уровня комфорта, а также от масштабируемости и читабельности. Что принесет пользу команде, так сказать.

...