2013-03-19 2 views
0

Я использую DataAdapter Batch для вставки на многие ко многим таблицы партия размер = 1000Вставка с помощью хранимой процедуры очень медленно

У меня есть 3 таблицы

  1. ШКОЛА (ID, Имя)
  2. СТУДЕНТ (ID, Имя)
  3. SCHOOL_STUDENT (SCHOOL_ID, student_id)

Я пытаясь вставить около 700K строк таблицы SCHOOL_STUDENT, но это очень медленно я передаю название школы и имя студента к хранимой процедуре

(
@schoolName varchar(100), 
@studentName varchar(50) 
) 

AS 
BEGIN transaction 

    declare @scoolId int,@studentId int 

    set @scoolId = (select ID from SCHOOL where [SCHOOL_NAME] = @schoolName) 
    set @studentId = (select ID from STUDENT where STUDENT_NAME = @studentName) 

    INSERT INTO [dbo].SCHOOL_STUDENT 
        (SCHOOL_ID,STUDENT_ID) 
      VALUES 
        (@scoolId,@studentId) 

commit transaction 

, но это занимает около 1 часа, чтобы бежать. Как я могу это ускорить, , так как я не знаю school_Id ни student_Id заранее, то я должен всегда выбирать их внутри хранимой процедуры. (есть ли лучший способ)

поток приложения сначала вставляет всех учеников, затем вставляют все школы, а затем связывают их в таблице school_student.

+1

Вам, вероятно, понадобятся некоторые индексы на вашей таблице ШКОЛЫ и СТУДЕНТА. Вероятно, один для SCHOOL.Id, SCHOOL.SCHOOL_NAME и STUDENT.ID, STUDENT.NAME. – Romoku

+0

Похоже, что у вас нет индекса, установленного на таблице 'SCHOOL'. – Dai

ответ

3

В порядке эффективности/результативности и усилий, возможно, попробовать:

1- Проверьте индексацию на столах вы читаете. Обеспечьте индексы в столбцах ID и имени каждой таблицы.

2- реорганизовать ХП, как это:

INSERT INTO dbo.School_Student(School_ID, Student_ID) 
    SELECT SC.ID, ST.ID 
    FROM dbo.School AS SC 
    JOIN dbo.Student AS ST ON ST.Student_Name = @studentName 
          AND SC.School_Name = @schoolName; 

3- Удалить сделку с технологич

4 натяг все ID школы и студент ID перед вызовом этого прок. Пропустите и передайте идентификатор.

5- Исследуйте операцию объемной копии SQL.

+0

Я не могу передать dataTable в хранимую процедуру, используя массовое копирование . Сейчас я тестирую TVP для выполнения upsert из 900 000 строк, . Я ищу почти 2 часа, чтобы найти способ использовать bulkCopy, передавая таблицу хранимой процедуре затем используя слияние. или я смотрю в неправильном направлении. – Maro

0

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

Измените процедуру, чтобы принять xml или синтаксисы с разделителями, которые вы можете передавать от 100 до 500 в каждой партии.

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

Последнее, выполните процедуру хранения, которая будет вставлять ВСЕ запись из промежуточной таблицы в транзакционную/главную таблицу. Использование select из таблицы с большими записями выполняется лучше, чем выбор 1 на 1.

Не забудьте повторно проверить данные, прежде чем делать вставку из постановки к транзакции/основной таблице, проверьте нулевой (не найдено) данные, дублирующие данные, поврежденные данные из-за разделитель строки или т.п.

Наконец, как упоминалось в вашем комментарии, выполните некоторую индексацию и настройку производительности для лучшей производительности. Он должен дать вам время выполнения менее 10 минут при правильном обращении.

2

Чтобы оптимизировать поиск, вам необходимо создать индексы на ваших школьных и школьных таблицах. Я бы также поставил ваши данные в таблицу и использовал SqlBulkCopy из C#, чтобы загрузить его. Хранимая процедура может преобразовывать данные и вставлять ключи.

CREATE PROCEDURE spSchoolStudentTransform 
AS 
BEGIN 

    INSERT INTO [dbo].[School_Student](School_Id, Student_Id) 
    SELECT School.Id, Student.Id FROM SchoolStudent ss 
    JOIN School 
    ON School.School_Name = ss.SchoolName 
    JOIN Student 
    ON Student.Student_Name = ss.StudentName; 

    TRUNCATE TABLE SchoolStudent; 
END 
GO 

CREATE TABLE SchoolStudent 
(
    Id INT IDENTITY PRIMARY KEY 
    ,StudentName VARCHAR(50) NOT NULL 
    ,SchoolName VARCHAR(100) NOT NULL 
); 
GO 

CREATE NONCLUSTERED INDEX ixStudentIdStudentName 
ON Student (Id, Student_Name); 
GO 

CREATE NONCLUSTERED INDEX ixSchoolIdSchoolName 
ON School (Id, School_Name); 
GO 

using (var connection = new SqlConnection(connectionString)) 
{ 
    using(var sqlBulkCopy = new SqlBulkCopy(connection)) 
    { 
     sqlBulkCopy.DestinationTableName = "SchoolStudent"; 
     sqlBulkCopy.EnableStreaming = true; 
     sqlBulkCopy.BatchSize = 1000; 

     sqlBulkCopy.WriteToServer(dataReader); 
    } 
} 
+0

В коде C# вы копируете результаты только в таблицу temp SchoolStudent, но где вы вызываете spSchoolStudentTransform, который копирует результаты из таблицы temp в реальную таблицу и затем усекает временную таблицу. – Maro

+0

Вам решать, когда ее называть. Вы можете сделать это с C# или Sql или просто нажать кнопку на какой-либо веб-странице, которая это сделает. – Romoku

+0

Мне нравится пример, который вы дали, особенно у меня нет опыта с SqlBulkCopy. обычно это пакетное приложение, которое должно запускаться без взаимодействия с пользователем, сначала вставлять все столы, затем все школы, а затем школы. также, что такое dataReader, noramlly, я должен пройти datatable правильно? я сожалею обо всех этих вопросах :-) – Maro

Смежные вопросы