Ошибка импорта StackOverflow: LOB превышает 2 147 483 647 байт? - PullRequest
3 голосов
/ 22 сентября 2009

После загрузки сентября 2009 года дампа данных StackOverflow и выполнения запроса импорта Brent я получаю следующее сообщение:

Msg 7119, Level 16, State 1, Procedure sp_xml_preparedocument, Line 1
Attempting to grow LOB beyond maximum allowed size of 2,147,483,647 bytes.
Msg 8179, Level 16, State 5, Procedure usp_ETL_Load_Posts, Line 59
Could not find prepared statement with handle 0.
The statement has been terminated.
Msg 7102, Level 20, State 99, Procedure usp_ETL_Load_Posts, Line 121
Internal Error: Text manager cannot continue with current statement. 
    Run DBCC CHECKTABLE.

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

Помимо получения более старых данных, кто-нибудь знает, как это исправить или импортировать данные другим способом?

ОБНОВЛЕНИЕ: Я работаю "Версия: Microsoft SQL Server 2005 - 9.00.1399.06 (Intel X86) 14 октября 2005 00:33:37 Copyright (c) 1988-2005 Microsoft Corporation Developer Edition on Windows NT 5.1 (сборка 2600: пакет обновления 3) "

Ответы [ 3 ]

2 голосов
/ 22 сентября 2009

Я справился с проблемой, написав небольшое консольное приложение в .Net (следующий код). Он импортирует записи по 1 за раз (даже не занимая время, чтобы связываться с объектом sqlbulkcopy) и запускается, пока я ухожу на обеденный перерыв. Я забыл записать метки времени на консоль, поэтому точно не знаю, сколько времени это заняло. Моя лучшая оценка чуть более 20 минут. Имейте в виду, что следующая проблема - это tempdb: если оставить настройки по умолчанию, то при импорте tempdb вырастет очень сильно. По завершении вы захотите перезапустить службу сервера sql.

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Xml;
namespace ImportPostsTable
{
    class Program
    {
        //TODO: pull connection string, data path from app.config or command line
        static string cnString = "Data Source=localhost;Database=SO;Trusted_Connection=True;";
        static string dataPath = @"C:\temp"; 
        static string insertString = "INSERT INTO Posts VALUES (@Id, @PostTypeID, @AcceptedAnswerId, @CreationDate, @Score, @ViewCount, @Body, @OwnerUserId, @OwnerDisplayName, @LastEditorUserId, @LastEditDate, @LastActivityDate, @Title, @Tags, @AnswerCount, @CommentCount, @FavoriteCount, @ClosedDate, @ParentId)";
        static void Main(string[] args)
        {
            Trace.Listeners.Add(new ConsoleTraceListener());

            try
            {
                 ImportPosts(dataPath, cnString);
            }
            catch (Exception e)
            {
                Trace.WriteLine(e.Message);
                Trace.WriteLine(e.StackTrace);
            }
            Console.ReadKey(true);
        }

        public static void ImportPosts(string XmlPath, string ConnectionString)
        {
            using (StreamReader sr = new StreamReader(Path.Combine(XmlPath, "posts.xml")))
            using (XmlTextReader rdr = new XmlTextReader(sr))
            using (SqlConnection cn = new SqlConnection(ConnectionString))
            using (SqlCommand cmd = new SqlCommand(insertString, cn))
            {
                cmd.Parameters.Add("@Id", SqlDbType.Int);
                cmd.Parameters.Add("@PostTypeId", SqlDbType.Int);
                cmd.Parameters.Add("@AcceptedAnswerId", SqlDbType.Int);
                cmd.Parameters.Add("@CreationDate", SqlDbType.DateTime);
                cmd.Parameters.Add("@Score", SqlDbType.Int);
                cmd.Parameters.Add("@ViewCount", SqlDbType.Int);
                cmd.Parameters.Add("@Body", SqlDbType.NVarChar);
                cmd.Parameters.Add("@OwnerUserId", SqlDbType.Int);
                cmd.Parameters.Add("@OwnerDisplayName", SqlDbType.NVarChar, 40);
                cmd.Parameters.Add("@LastEditorUserId", SqlDbType.Int);
                cmd.Parameters.Add("@LastEditDate", SqlDbType.DateTime);
                cmd.Parameters.Add("@LastActivityDate", SqlDbType.DateTime);
                cmd.Parameters.Add("@Title", SqlDbType.NVarChar, 250);
                cmd.Parameters.Add("@Tags", SqlDbType.NVarChar, 150);
                cmd.Parameters.Add("@AnswerCount", SqlDbType.Int);
                cmd.Parameters.Add("@CommentCount", SqlDbType.Int);
                cmd.Parameters.Add("@FavoriteCount", SqlDbType.Int);
                cmd.Parameters.Add("@ClosedDate", SqlDbType.DateTime);
                cmd.Parameters.Add("@ParentId", SqlDbType.Int);

                Trace.Write(DateTime.Now.ToString() + Environment.NewLine + "Reading");
                int count = 0;
                cn.Open();
                while (rdr.Read())
                {
                    if (rdr.AttributeCount <= 5) continue; //everything but the xml declaration and the root element will have at least 5 attributes

                    cmd.Parameters[0].Value = rdr["Id"];
                    cmd.Parameters[1].Value = rdr["PostTypeId"];
                    cmd.Parameters[2].Value = rdr["AcceptedAnswerId"];
                    cmd.Parameters[3].Value = ParseDate(rdr["CreationDate"]);
                    cmd.Parameters[4].Value = rdr["Score"];
                    cmd.Parameters[5].Value = rdr["ViewCount"];
                    cmd.Parameters[6].Value = rdr["Body"];
                    cmd.Parameters[7].Value = rdr["OwnerUserId"];
                    cmd.Parameters[8].Value = rdr["OwnerDisplayName"];
                    cmd.Parameters[9].Value = rdr["LastEditorUserId"];
                    cmd.Parameters[10].Value = ParseDate(rdr["LastEditDate"]);
                    cmd.Parameters[11].Value = ParseDate(rdr["LastActivityDate"]);
                    cmd.Parameters[12].Value = rdr["Title"];
                    cmd.Parameters[13].Value = rdr["Tags"];
                    cmd.Parameters[14].Value = rdr["AnswerCount"];
                    cmd.Parameters[15].Value = rdr["CommentCount"];
                    cmd.Parameters[16].Value = rdr["FavoriteCount"];
                    cmd.Parameters[17].Value = ParseDate(rdr["ClosedDate"]);
                    cmd.Parameters[18].Value = rdr["ParentId"];

                    for (int i = 0; i < cmd.Parameters.Count; i++)
                        if (cmd.Parameters[i].Value == null)
                            cmd.Parameters[i].Value = DBNull.Value;

                    cmd.ExecuteNonQuery();

                    if (count++ % 5000 == 0) Trace.Write(".");
                }
                Trace.WriteLine(string.Format("\n\n{0:d}\nFinished {1} records.", DateTime.Now, count));
            }
        }

        public static object ParseDate(string dateValue)
        {
            if (string.IsNullOrEmpty(dateValue)) return DBNull.Value;
            return DateTime.ParseExact(dateValue, "yyyy-MM-ddTHH:mm:ss.fff", null);
        }
    }
}
1 голос
/ 22 сентября 2009

Все, что вам нужно сделать, это разбить файл поста на 2-3 файла, и вы все равно можете использовать запрос импорта, который вы использовали.

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

1 голос
/ 22 сентября 2009

SQL Server не имеет данных любого типа, способных хранить более 2 гигабайт данных в столбце строки.

Базы данных (кроме Express Editions) могут хранить намного больше 2 ГБ, если у вас достаточно места на диске, но применяется ограничение на объем данных в столбце строки.

...