Медленные вставки из SQL Server в MySQL Linked Server - PullRequest
1 голос
/ 16 февраля 2011

Мы выполняем своего рода репликацию по собственной инициативе из базы данных SQL Server 2008 R2 в базу данных MySQL 5.1. Это неверная репликация, поскольку блок MySQL действует как постоянное хранилище, а SQL Server - это то, что мы вынуждены использовать в качестве агрегатора данных.

Итак, я написал хранимую процедуру, которая проверяет последнюю строку, вставленную в мою таблицу, о которой идет речь, в базе данных MySQL, заполняет временную таблицу на конце SQL Server новой партией строк для вставки обратно в блок MySQL. и делает вставки. Проблема в том, что это мучительно медленно. У меня есть отставание> 24 миллионов строк для отправки из коробки SQL Server в MySQL, и со скоростью, с которой я получаю <2 строки в секунду, для завершения потребуется почти 6 месяцев, и я никогда не смогу быть в курсе с новыми данными при попадании в базу данных SQL Server. </p>

Ящики не находятся в одной и той же сети - ящик MySQL стоит чертовски близко к подключению страны к магистрали Интернета, но ящик SQL Server (по независящим от нас причинам) подключен только через линию бизнес-DSL ( не позитив скорости восходящего потока). Если я подключаюсь через командную строку (в отличие от запросов через связанный сервер в SQL Server), я могу вставлять строки в базу данных MySQL в среднем ~ 0,03 секунды на строку. Это наводит меня на мысль, что либо моя хранимая процедура просто невероятно неэффективна, либо OPENQUERY / Linked Servers по своей сути просто медленны. Вот хранимая процедура:

DECLARE @LastSensorLogDateFormatted DATETIME
DECLARE @LastSensorLogDate VARCHAR(30)
DECLARE @LastSensorLogMillis INT
DECLARE @LastSensorLogEibaddress VARCHAR(30)
DECLARE @SensorLogReplicated BIGINT
DECLARE @counter INT

-- Create a temporary table to store last write 
-- to MySQL database on CASALA-DB01
CREATE TABLE #SensorLogRecord 
  (LastSensorLogDate VARCHAR(30)
  , LastSensorLogMillis INT
  , LastSensorLogEibaddress VARCHAR(30))            

-- Dump result of query on CASALA-DB01 into our temporary table
INSERT INTO #SensorLogRecord
  (LastSensorLogDate, LastSensorLogMillis, LastSensorLogEibaddress )
  (SELECT  date, date_millis, eib_address
  FROM 
    OPENQUERY(MYSQL4, 'SELECT date, date_millis, eib_address 
    FROM cabie.sensors_log_redux ORDER BY date desc LIMIT 1'))

-- Store the last sensor log date and EIB address 
-- from our temporary table into local vars
SELECT 
  @LastSensorLogDate = LastSensorLogDate, 
  @LastSensorLogMillis = LastSensorLogMillis, 
  @LastSensorLogEibaddress = LastSensorLogEibaddress 
FROM #SensorLogRecord

SET @LastSensorLogDateFormatted = 
    CAST((LEFT(@LastSensorLogDate, 20) + 
    CAST(@LastSensorLogMillis as VARCHAR)) AS DATETIME)

SET @counter = 0            
WHILE (1=1)
  BEGIN
    CREATE TABLE #RecordHolder (Id BIGINT)

    INSERT INTO #RecordHolder (Id)
      SELECT TOP 1000 Sensor_Id FROM dbo.Sensors_Log
      WHERE Sensor_Id NOT IN (SELECT * FROM dbo.Sensors_Archivals)
      AND dbo.Sensors_Log.Date <= GETDATE()
      AND dbo.Sensors_Log.EibAddress <> @LastSensorLogEibaddress
      AND dbo.Sensors_Log.Date <> @LastSensorLogDateFormatted

  INSERT OPENQUERY(MYSQL4, 
    'SELECT date, eib_address, ip_address, value, application, phys_address 
    FROM sensors_log_redux_holding')        
  SELECT 
    CONVERT(VARCHAR, GNH.dbo.Sensors_Log.Date,121),
    GNH.dbo.Sensors_Log.EibAddress,
    GNH.dbo.Sensors_Log.Ip_Address,
    GNH.dbo.Sensors_Log.Value,
    GNH.dbo.Sensors_Log.Application,
    GNH.dbo.Sensors_Log.Phys_Address 
  FROM GNH.dbo.Sensors_Log 
  JOIN #RecordHolder  
    ON (#RecordHolder.Id = GNH.dbo.Sensors_Log.Sensor_Id)

  INSERT INTO dbo.Sensors_Archivals (Row_Id) SELECT Id FROM #RecordHolder

  DROP TABLE #RecordHolder  

  IF (@counter >= 1000000)
   BREAK
END

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

РЕДАКТИРОВАТЬ: Вот мои настройки сервера:

  • Провайдер: Microsoft OLE Provider for ODBC Drivers
  • Наименование продукта: MySQL 5.1
  • Строка поставщика: DRIVER={MySQL ODBC 5.1 Driver};SERVER=192.168.17.5;DATABASE=cabie;USERNAME=ourUsername;PASSWORD=ourPassword
  • Дополнительные параметры:
    • Совместимость: FALSE
    • Доступ к данным: TRUE
    • RPC: FALSE
    • RPC Out: FALSE
    • Использовать дистанционную сортировку: TRUE
    • Имя сопоставления: (Blank)
    • Время ожидания соединения: 0
    • Тайм-аут запроса: 0
    • Дистрибьютор: FALSE
    • Издатель: FALSE
    • Подписчик: FALSE
    • Ленивая проверка схемы: FALSE
    • Включить продвижение распределенных транзакций: TRUE

1 Ответ

0 голосов
/ 15 апреля 2011

Вот часть проблемы ...

# Provider: Microsoft OLE Provider for ODBC Drivers
# Provider String: DRIVER={MySQL ODBC 5.1 Driver};...

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

Альтернативным подходом было бы написать приложение на Delphi или C (#). Если это приложение подключается с помощью собственного клиента DLL к базе данных.

Я знаю, что Delphi с базой данных ZEOS с открытым исходным кодом, использующей свободно доступный клиентский dll от Microsoft и MySQL, будет передавать данные во много раз быстрее, чем ODBC.

Также C # или любой современный язык программирования, который использует нативный клиентский DLL с SQL, сделает эту работу. Убедитесь, что если вы используете промежуточную программу для связи между двумя базами данных, чтобы она не возвращалась к ODBC, многие (в основном более старые) среды программирования делают это из-за лени или дешевизны с теми же дрянными скоростями передачи, которые вы получаете. Теперь.

Надеюсь, это поможет ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...