SQL.RU
 client/server technologies
Rambler's Top100
 Главная | Документация | Статьи | Книги | Форум | Опросы | Каталог | Гостевая | Рассылка | Работа | Поиск | FAQ |
XML в MS SQL Server 2000 и технологиях доступа к данным | XML Bulk Load Дальше »

Большие объемы данных неэффективно "заливать" в базу чередой последовательных insert'ов. Для этого применяются средства массовой загрузки. Аналогом bcp / BULK INSERT при работе с XML-файлами выступает XML Bulk Load. Он не грузит весь документ целиком в память, а прочитывает его по отдельным узлам, понимая на основе аннотированной схемы, когда запись заканчивается и ее можно отправить SQL Server'у для вставки. Использование аннотированных схем позволяет осуществлять наполнение одновременно нескольких связанных таблиц. XML Bulk Load не есть утилита с графическим интерфейсом, а всего лишь СОМ-компонент, устанавливаемый SQLXML веб-релизами. Массовая закачка XML-документа осуществляется программным путем - достаточно написать VB-скрипт из нескольких строчек. Я надеюсь, что эта идея вас не пугает, потому что если вы дочитали до этого места, значит, вы, скорее, разработчики, нежели пользователи или администраторы. Для работы из-под .NET Framework необходимо импортировать библиотеку типов Microsoft SQLXML Bulkload 3.0 Type Library (...\Program Files\Common Files\System\Ole DB\xblkld3.dll).
Объектная модель XML Bulk Load тривиальна. Она состоит из единственного объекта - SQLXMLBulkLoad с единственным методом Execute, принимающим два параметра: аннотированную схему и сам XML-документ. Аннотированная схема, как всегда, задает правила разноски XML- содержания: в какое поле какой таблицы положить тот или иной элемент или атрибут. Собственно, все.
Вот XML, который требуется перенести в БД:


<Книги_по_XML>
    <Книга Название="The Guru's Guide to SQL Server Stored Procedures, 
	XML, and HTML" ISBN="0201700468" Страниц<font color=blue>="576">
        <Порядковый_номер>1</Порядковый_номер>
        <Издательство>Wesley Professional</Издательство>
        <Цена_на_Амазоне>34.99</Цена_на_Амазоне>
        <Дата_выхода>2001-12-21</Дата_выхода>
        <Авторы>
            <Автор Имя="Ken" Фамилия="Henderson" />
            <Автор Имя="Ron" Фамилия="Soukup" />
        </Авторы>
    </Книга>
    <Книга Название="Programming Microsoft SQL Server 2000 With XML 
	(Pro-Developer)" ISBN="0735613699" Страниц="400">
        <Порядковый_номер>2</Порядковый_номер>
        <Издательство>Microsoft Press</Издательство>
        <Цена_на_Амазоне>41.99</Цена_на_Амазоне>
        <Дата_выхода>2001-06-01</Дата_выхода>
        <Авторы>
            <Автор Имя="Graeme" Фамилия="Malcolm" />
        </Авторы>
    </Книга>
...
</Книги_по_XML>

Вот аннотированная схема, которую я для него определил (схема должна находиться в отдельном файле, размещение ее в самом XML-документе не допускается).


<?xml version="1.0" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:ms="urn:schemas-microsoft-com:mapping-schema">
	<xs:annotation>
		<xs:appinfo>
			<ms:relationship name="Книга_Авторы" parent="Book" 
			parent-key="BookID" child="Author" child-key="BookID" />
		</xs:appinfo>
	</xs:annotation>
	<xs:element name="Книга" ms:relation="Book">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="Порядковый_номер" 
				ms:field="BookID" ms:datatype="int" />
				<xs:element name="Издательство" 
				ms:field="Publishing" ms:datatype="varchar(50)" />
				<xs:element name="Цена_на_Амазоне" 
				ms:field="Price" ms:datatype="numeric(6,2)" />
				<xs:element name="Дата_выхода" 
				ms:field="IssueDate" ms:datatype="smalldatetime" />
				<xs:element name="Авторы" 
				maxOccurs="1" ms:is-constant="1">
					<xs:complexType>
						<xs:sequence>
							<xs:element name="Автор" minOccurs="0" 
							maxOccurs="unbounded" ms:relation="Author" 
							ms:relationship="Книга_Авторы">
								<xs:complexType>
									<xs:attribute name="Имя" 
									ms:field="FirstName" 
									ms:datatype="nvarchar(50)" />
									<xs:attribute name="Фамилия" 
									ms:field="LastName" 
									ms:datatype="nvarchar(50)" />
								</xs:complexType>
							</xs:element>
						</xs:sequence>
					</xs:complexType>
				</xs:element>
			</xs:sequence>
			<xs:attribute name="Название" ms:field="Title" 
			ms:datatype="nvarchar(200)" />
			<xs:attribute name="ISBN" ms:field="ISBN" 
			ms:datatype="char(10)" />
			<xs:attribute name="Страниц"
			ms:field="NumPages" ms:datatype="smallint" />
		</xs:complexType>
	</xs:element>
</xs:schema>

И вот скрипт, который осуществляет загрузку:


class BulkExample
{
	static void BulkLoad_File_SQLXML()
	{
		SQLXMLBULKLOADLib.SQLXMLBulkLoad3Class bl = 
		new SQLXMLBULKLOADLib.SQLXMLBulkLoad3Class();
		bl.ConnectionString = "Provider=SQLOLEDB;...";
		bl.SchemaGen = true;
		bl.SGDropTables = true;
		bl.KeepNulls = true;
		bl.Transaction = true;
		bl.ErrorLogFile = "..\\BulkCopy\\XMLDocForBulkLoad.err";
		bl.Execute("..\\BulkCopy\\XMLDocForBulkLoad.xsd", 
		"..\\BulkCopy\\XMLDocForBulkLoad.xml");
	}

	[STAThread]
	static void Main()
	{
		BulkLoad_File_SQLXML();
	}
}

Скрипт 13

Следует обратить внимание на атрибут [STAThread], поскольку компонент пока работает только в однопоточном режиме. Свойство SchemaGen, определяет, должны ли таблицы под загрузку создаваться или вставка идет в уже имеющиеся. Чтобы просто создать структуры и не переносить при этом сами данные, нужно еще поставить BulkLoad = false. Имена таблиц и полей, их типы и прочие метаданные определяются аннотированной схемой (ms:relation, ms:field, ms:datatype). Если таблицы уже существуют, то SGDropTables = true заставляет их пересоздаться. Удаление таблиц происходит в том порядке, в котором они упоминаются в XML-файле и может приводить к конфликту с ограничениями primary key/foreign key. Рассмотренный в п.11 ms:inverse при этом не помогает. В том случае, если таблица есть и для поля определено значение по умолчанию, оно будет использоваться, когда в XML-файле соответствующий элемент или атрибут пропущен, но если поставить KeepNulls = true, то значение по умолчанию будет проигнорировано и в поле будет поставлен Null. Аналогично действует свойство KeepIdentity. Если вставка идет в поле типа identity, то false заставляет игнорировать значения для этого поля в XMLном файле и использовать автоинкремент, определенный для него на сервере. CheckConstraints определяет, будут ли проверяться constraints (primary key/foreign key и пр.) при загрузке данных. Свойство Transaction заставляет все действия по загрузке проходить в масштабе единой транзакции, так что ежели что случится, то все будет откачено. Его нельзя использовать при загрузке BLOBов. ForceTableLock устанавливает табличную блокировку на таблицы, задействованные в ходе bulk load. Если в аннотированной схеме поле помечено атрибутом dt:type="id" (xmlns:dt="urn:schemas-microsoft-com:xml:datatypes"), то свойство SGUseID = true приведет к тому, что при создании таблицы на него будет создано ограничение primary key. Если в схеме в <xs:element name<font color=blue>="Книга" ms:relation="Book"> поставить атрибут, ms:key-fields="BookID", то между таблицами Book и Author будет создано ограничение primary key/foreign key по полю BookID. Независимо от этого указание в схеме отношения между таблицами <ms:relationship name="Книга_Авторы" parent="Book" parent-key="BookID" child="Author" child-key="BookID" /> обеспечивает во время массовой загрузки автоматическое заполнение поля BookID в дочерней таблице Author значениями BookID из родительской записи таблицы Book, как происходит в нашем случае:

BookID Publishing Price IssueDate NumPages ISBN Title
1.Wesley Professional34.992001-12-21 00:00:005760201700468 The Guru's Guide to SQL Server Stored Procedures, XML, and HTML
2.Microsoft Press41.992001-06-01 00:00:004000735613699 Programming Microsoft SQL Server 2000 With XML (Pro-Developer)
.....................

LastName FirstName BookID
HendersonKen1
SoukupRon1
MalcolmGraeme2
GriffinJohn3
WilliamsKevin4
.........

Методу Execute можно передавать не только название XML-документа, но и ADODB.Stream:


...

StreamReader sr = File.OpenText("..\\BulkCopy\\XMLDocForBulkLoad.xml");
ADODB.StreamClass sc = new ADODB.StreamClass();
sc.Charset = "UTF-8"; 
sc.Open(System.Type.Missing, ADODB.ConnectModeEnum.adModeUnknown, 
ADODB.StreamOpenOptionsEnum.adOpenStreamUnspecified, "", "");
sc.WriteText(sr.ReadToEnd(), ADODB.StreamWriteEnum.stWriteChar);
sc.Position = 0;
bl.Execute("..\\BulkCopy\\XMLDocForBulkLoad.xsd", sc);
sr.Close(); sc.Close();

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

XML в MS SQL Server 2000 и технологиях доступа к данным | XML Bulk Load Дальше »
Rambler's Top100 Parking.ru Рейтинг@Mail.ru  Administrator: admin@sql.ru 
Last update: 07 окт 2003 
Hosted by uCoz