我们正在进行一种从 SQL Server 2008 R2 数据库到 MySQL 5.1 数据库的自行复制。这不是真正的复制,因为 MySQL 框充当永久存储,而 SQL Server 是我们被迫用作数据聚合器的东西。
因此,我编写了一个存储过程,用于检查在 MySQL 数据库中插入到我的相关表中的最新行,在 SQL Server 端填充一个临时表,并用一批新行插入回 MySQL 框, 并插入。问题是,这太慢了。我有超过 2400 万行的积压要从 SQL Server 框发送到 MySQL,并且以我得到 <2 行/秒的速度,将需要将近 6 个月才能完成并且永远无法跟上在新数据到达 SQL Server 数据库时使用新数据。
这些盒子不在同一个网络上——MySQL 盒子非常靠近国家与互联网主干网的连接,但 SQL Server 盒子(出于我们无法控制的原因)仅通过商业 DSL 线路连接(对上游速度不利)。如果我通过命令行连接(而不是通过 SQL Server 中的链接服务器进行查询),我能够以平均每行约 0.03 秒的速度在 MySQL 数据库中插入行。这让我相信要么我的存储过程效率低得令人难以置信,要么 OPENQUERY/链接服务器本身就很慢。这是存储过程:
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
我知道这很麻烦......我们一直在尝试不同的方法来让它工作,所以可能有未使用的变量等。就其值(value)而言,仅在链接服务器上运行第一个选择查询需要向上40 秒。
编辑:这是我的链接服务器设置:
- 提供程序:
用于 ODBC 驱动程序的 Microsoft OLE 提供程序
- 产品名称:
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 输出:
FALSE
- 使用远程整理:
TRUE
- 排序规则名称:
(空白)
- 连接超时:
0
- 查询超时:
0
- 经销商:
FALSE
- 发布者:
FALSE
- 订阅者:
FALSE
- 惰性架构验证:
FALSE
- 启用分布式事务的推广:
TRUE
- 排序规则兼容:
最佳答案
这是问题的一部分......
# Provider:用于 ODBC 驱动程序的 Microsoft OLE Provider
# Provider String: DRIVER={MySQL ODBC 5.1 Driver};...
ODBC 是出了名的慢,您在两端 都使用它。
另一种方法是用 Delphi 或 C(#) 编写应用程序。 如果此应用程序使用 native 客户端 dll 连接到数据库。
我知道带有开源 ZEOS 数据库的 Delphi 使用可从 Microsoft 和 MySQL 免费获得的客户端 dll,传输数据的速度将比 ODBC 快很多倍。
C# 或任何使用本地客户端 dll 和 SQL 的现代编程语言也可以完成这项工作。 确保如果您使用中间程序在两个数据库之间建立桥接,它不会回退到 ODBC,许多(主要是较旧的)编程环境出于懒惰或廉价而使用与您获得的相同糟糕的传输速度现在。
希望这有助于...
关于mysql - 从 SQL Server 到 MySQL 链接服务器的缓慢 INSERT,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5014740/