我有.sql文件(550 MB),我想将其导入到运行的mysql服务器。我知道mysql.exe的路径。
我的想法是模仿命令行导入mysql -u user -ppass db_name < file.sql
。这从命令行运行良好(我已设置高max_allowed_packet)。根据Stackoverflow上的另一个帖子,我发现这个工作:
Process process = new Process();
process.StartInfo.FileName = mysqlexepath;
process.StartInfo.Arguments = "-v -u user -ppassworddbname";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardInput = true;
try
{
process.Start();
StreamWriter input = process.StandardInput;
using (StreamReader sr = new StreamReader(sqlfilepath))
{
while ((line = sr.ReadLine()) != null)
{
if (process.HasExited == true)
throw new Exception("DB went away.");
input.WriteLine(line);
input.Flush();
}
}
process.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
我可以看到如何在DB中创建表。但我的问题是大约一半的过程退出。我正在谷歌搜索一些超时设置,但无法找到任何东西。
我还尝试先读取文件:
var file = FileInfo(sqlfilepath);
StreamReader reader = file.OpenText();
string fileContents = reader.ReadToEnd();
StreamWriter input = process.StandardInput;
input.AutoFlush = true;
input.Write(fileContents);
input.Close();
但是我得到了OutOfMemory异常。所以正确的方法并不能通过字符串。
我非常感谢任何建议如何找出问题所在。我甚至不知道它的进程超时或mysql超时或者问题是否在StreamReader中。
答案 0 :(得分:14)
我知道这不是您问题的直接答案,说实话,我不确定您的方法有什么问题。我可以通过分享我们如何使用mysql.exe运行非常大的sql脚本来帮助...
"C:\Program Files (x86)\MySQL\MySQL Server 5.0\bin\mysql.exe" -C -B --password=[password] -P 3306 --user=[username] --host=localhost --database=[database] -e "\. C:\Backups\Mybackup.sql"
这些参数中的大部分都是显而易见的,连接信息等。
显而易见的是,-e "\. [filename]"
-e
参数的神奇部分指明mysql应运行以下命令并退出。前缀"\. "
表示应使用输入文件,后跟该文件名。
我们使用它来恢复数千兆字节的数据库而不会出现问题。所以这里是完整的&#39;运行scirpt&#39;用mssql ...
public static int RunMySql(string server, int port, string user, string password, string database, string filename)
{
var process = Process.Start(
new ProcessStartInfo
{
FileName = @"C:\Program Files (x86)\MySQL\MySQL Server 5.0\bin\mysql.exe",
Arguments =
String.Format(
"-C -B --host={0} -P {1} --user={2} --password={3} --database={4} -e \"\\. {5}\"",
server, port, user, password, database, filename),
ErrorDialog = false,
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true,
WorkingDirectory = Environment.CurrentDirectory,
}
);
process.OutputDataReceived += (o, e) => Console.Out.WriteLine(e.Data);
process.ErrorDataReceived += (o, e) => Console.Error.WriteLine(e.Data);
process.Start();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
process.StandardInput.Close();
process.WaitForExit();
return process.ExitCode;
}
答案 1 :(得分:2)
我遇到了同样的问题并且使用已接受的解决方案太顽固了,尽管它已经两年没有受到挑战。此外,我想从.gz导入而不先将其解压缩到另一个文件(并且不想假设gzip可执行文件可用)。所以我找出了原始代码的错误。
MySQL转储文件可以有很长的行没有中断,所以我的猜测是ReadLine()
填充缓冲区而没有找到换行符,导致OutOfMemory
异常。因此,必须使用Read()
代替ReadLine()
来避免这种情况。
可能发生的另一个问题(我有)是在.sql文件中使用二进制blob,当将文本字符串从文件移动到stdin时,文本重新编码可能会搞乱,所以我&#39;修改了代码以避免使用读者或写入者,而是使用字节和二进制文件。
这是我的解决方案:
Process process = new Process();
process.StartInfo.FileName = mysqlexepath;
process.StartInfo.Arguments = "-v -u user -ppassworddbname";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardInput = true;
byte[] buffer = new byte[4096];
int count;
try
{
process.Start();
BinaryWriter stdinBinary = new BinaryWriter(process.StandardInput.BaseStream);
Stream fileStream;
if (sqlfilepath.EndsWith(".gz")) {
fileStream = new GZipStream(new FileStream(sqlfilepath, FileMode.Open, FileAccess.Read, FileShare.Read), CompressionMode.Decompress);
} else {
fileStream = new FileStream(sqlfilepath, FileMode.Open, FileAccess.Read, FileShare.Read);
}
using (fileStream)
{
while ((count = fileStream.Read(buffer, 0, buffer.Length)) > 0)
{
if (process.HasExited == true)
throw new Exception("DB went away.");
stdinBinary.Write(buffer, 0, count);
stdinBinary.Flush(); // probably not needed
}
}
stdinBinary.Flush();
process.Close();
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.Message);
}
我导入1.1 GB sql.gz数据库转储(3.5 GB未压缩)没有任何问题,但我欢迎任何代码改进。
答案 2 :(得分:0)
我遇到了很多问题,问题不是代码,代码是正确的,问题是虚拟内存的限制,计算机不支持使用每个进程内存大的文件。 Windows进程系统限制执行每个进程的内存量,以防止系统崩溃。
我不知道这个限制,因为它因每个计算机架构以及内存,总线等的数量而异。
您可以从文件中获得建议,按顺序创建表,读取一段运行,读取另一个运行,等等。
另一个想法是尝试在另一个线程或进程上并行工作,请注意:http://www.codeproject.com/Articles/189374/The-Basics-of-Task-Parallelism-via-C
答案 3 :(得分:0)
调试.NET应用程序时,windbg + SOS是一个很好的选择工具。
通过windbg启动您的程序
发生异常时,检查HEAP对象和CallStack到HEAP中的特定Exception对象,找到原因。 http://blogs.msdn.com/b/johan/archive/2007/01/11/i-am-getting-outofmemoryexceptions-how-can-i-troubleshoot-this.aspx
gcroot命令可以在HEAP中找到对象的引用。 http://blogs.msdn.com/b/tess/archive/2006/01/23/net-memory-leak-case-study-the-event-handlers-that-made-the-memory-baloon.aspx