简体   繁体   English

从SQL Server到MySQL链接服务器的INSERT速度慢

[英]Slow INSERTs from SQL Server to MySQL Linked Server

We're doing a sort of roll-your-own replication from a SQL Server 2008 R2 database to a MySQL 5.1 database. 我们正在执行一种从SQL Server 2008 R2数据库到MySQL 5.1数据库的自卷式复制。 This isn't true replication, as the MySQL box is acting as permanent storage and the SQL Server is what we're forced to use as a data aggregator. 这不是真正的复制,因为MySQL框充当永久性存储,而SQL Server被迫用作数据聚合器。

So, I've written a stored procedure that checks the latest row inserted on my table in question on the MySQL database, populates a temporary table on the SQL Server end with a new batch of rows to insert back on the MySQL box, and does the inserts. 因此,我编写了一个存储过程,该过程检查MySQL数据库中有问题的表上插入的最新行,在SQL Server端的临时表中填充一批新行,然后再插入MySQL框中,并执行插入物。 The problem is, this is painfully slow. 问题是,这太慢了。 I have a backlog of >24 million rows to send from the SQL Server box to MySQL, and at the rate I'm getting <2 rows/second, it's going to take nearly 6 months to complete and will never be able to keep up with new data as it hits the SQL Server database. 我有超过2400万行的积压从SQL Server盒发送到MySQL,并且以我每秒获得<2行的速度,它将需要近6个月才能完成,并且永远无法跟上在SQL Server数据库中添加新数据。

The boxes are not on the same network--the MySQL box sits pretty darn near the country's connection to the Internet back bone, but the SQL Server box is (for reasons beyond our control) only connected through a business DSL line (not positive of the upstream speed). 这些盒子不在同一个网络上-MySQL盒子位于该国与Internet骨干网的连接位置附近,但是SQL Server盒子(由于我们无法控制的原因)仅通过业务DSL线路连接(对上游速度)。 If I connect through the command line (as opposed to by querying through the linked server in SQL Server), I'm able to insert rows in the MySQL database at an average of ~0.03 seconds per row. 如果我通过命令行连接(而不是通过SQL Server中的链接服务器进行查询),则可以在MySQL数据库中平均每行插入约0.03秒。 This leads me to believe that either my stored procedure is just incredibly inefficient, or OPENQUERY/Linked Servers are just inherently slow. 这使我相信要么我的存储过程效率非常低,要么OPENQUERY / Linked Servers本质上很慢。 Here is the stored procedure: 这是存储过程:

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

I know that's messy...we've been trying different approaches to getting this to work, so there are probably unused variables, etc. For what it's worth, just running a that first select query on the linked server takes upwards of 40 seconds. 我知道这很杂乱……我们一直在尝试不同的方法来使其正常工作,因此可能存在未使用的变量等。为此,仅在链接服务器上运行第一个选择查询就需要40秒钟以上的时间。

EDIT: Here's my linked server setup: 编辑:这是我的链接服务器设置:

  • Provider: Microsoft OLE Provider for ODBC Drivers 提供程序: Microsoft OLE Provider for ODBC Drivers
  • Product Name: MySQL 5.1 产品名称: MySQL 5.1
  • Provider String: DRIVER={MySQL ODBC 5.1 Driver};SERVER=192.168.17.5;DATABASE=cabie;USERNAME=ourUsername;PASSWORD=ourPassword 提供程序字符串: DRIVER={MySQL ODBC 5.1 Driver};SERVER=192.168.17.5;DATABASE=cabie;USERNAME=ourUsername;PASSWORD=ourPassword
  • Advanced Options: 高级选项:
    • Collation Compatible: FALSE 排序规则兼容: FALSE
    • Data Access: TRUE 数据访问: TRUE
    • RPC: FALSE RPC: FALSE
    • RPC Out: FALSE RPC输出: FALSE
    • Use Remote Collation: TRUE 使用远程整理: TRUE
    • Collation Name: (Blank) 归类名称:( (Blank)
    • Connection Timeout: 0 连接超时: 0
    • Query Timeout: 0 查询超时: 0
    • Distributor: FALSE 发行人: FALSE
    • Publisher: FALSE 发布者: FALSE
    • Subscriber: FALSE 订阅者: FALSE
    • Lazy Schema Validation: FALSE 惰性模式验证: FALSE
    • Enable Promotion of Distributed Transactions: TRUE 启用促销分布式事务: TRUE

Here's part of the problem... 这是问题的一部分...

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

ODBC is famously slow and you are using it on both ends. ODBC是著名的慢,你正在使用它的两端

An alternative approach would be to write an application in Delphi or C(#). 一种替代方法是用Delphi或C(#)编写应用程序。 If this application connects using native client dll's to the database. 如果此应用程序使用本机客户端dll连接到数据库。

I know that Delphi with the open source ZEOS database using the client dll's freely available from Microsoft and MySQL will transfer data many times faster than ODBC will do. 我知道,使用Microsoft和MySQL免费提供的使用客户端dll的开源ZEOS数据库的Delphi,数据传输的速度比ODBC快许多倍。

Also C# or any modern programming language that uses the native client dll's with SQL will do the job. 同样,C#或任何将本机客户端dll与SQL结合使用现代编程语言都可以胜任。 Make sure that if you use a in-between program to bridge between the two databases that it does not fall back to ODBC, lots of (mainly older) programming environments do this out of lazyness or cheapness with the same crappy transfer speeds that your getting now. 确保如果使用中间程序在两个数据库之间架桥而不会退回到ODBC,则许多(主要是较旧的)编程环境出于懒惰或便宜的考虑而这样做,并且传输速度与获取时相同现在。

Hope this helps... 希望这可以帮助...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM