我有 4 个 MySQL 表,它们通过FOREIGN KEYs 相互依赖。
请检查以下表结构架构:
CREATE DATABASE IF NOT EXISTS courses
CHARACTER SET latin1
COLLATE latin1_bin;
CREATE TABLE IF NOT EXISTS courses.institution
(
icode INT UNSIGNED NOT NULL AUTO_INCREMENT,
iname VARCHAR(255) NOT NULL,
PRIMARY KEY (icode),
UNIQUE (iname)
)
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS courses.cities
(
ccode INT UNSIGNED NOT NULL AUTO_INCREMENT,
cname VARCHAR(255) NOT NULL,
PRIMARY KEY (ccode),
UNIQUE (cname)
)
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS courses.skills
(
scode INT UNSIGNED NOT NULL AUTO_INCREMENT,
sname VARCHAR(255) NOT NULL,
PRIMARY KEY (scode),
UNIQUE (sname)
)
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS courses.relation
(
icode INT UNSIGNED NOT NULL,
scode INT UNSIGNED NOT NULL,
ccode INT UNSIGNED NOT NULL,
UNIQUE KEY ucols (icode, scode, ccode),
FOREIGN KEY (icode) REFERENCES courses.institution (icode),
FOREIGN KEY (scode) REFERENCES courses.skills (scode),
FOREIGN KEY (ccode) REFERENCES courses.cities (ccode)
)
ENGINE = InnoDB;
目前我正在执行下面的查询以在relation 表中插入一条记录。
每次只插入一次,需要 4 个 INSERT 查询和 3 个 SELECT 子查询。
INSERT IGNORE INTO institution(iname) VALUES ('ABC Learners');
INSERT IGNORE INTO skills(sname) VALUES ('PHP');
INSERT IGNORE INTO cities(cname) VALUES ('Bangalore');
INSERT IGNORE INTO relation (icode, scode, ccode) VALUES (
(SELECT icode FROM institution WHERE iname = 'ABC Learners'),
(SELECT scode FROM skills WHERE sname = 'PHP'),
(SELECT ccode FROM cities WHERE cname = 'Bangalore')
);
Is it necessary to execute all this queries every time? or is there any better way to perform this action in single or few queries?
检查下面的简单 PHP 代码。在这段用于在 relation 表上插入 7 条记录的代码中,它执行 4 INSERT 查询,每条记录上有 3 SELECT 子查询。
7 条记录总共需要 7 * 7 = 49 次查询。如何解决?
<?php
$db = new mysqli('localhost', 'user', '****', 'courses');
$records = [
['ABC Learners', 'CSS', 'Bangalore'],
['ABC Learners', 'PHP', 'Bangalore'],
['ABC Learners', 'HTML', 'Bangalore'],
['ABC Learners', 'PHP', 'Hyderabad'],
['XYZ Solutions', 'PHP', 'Hyderabad'],
['XYZ Solutions', 'JAVA', 'Hyderabad'],
['XYZ Solutions', 'JAVA', 'Bangalore'],
];
foreach ($records as $record) {
list($institute, $skill, $city) = $record;
$db->query("INSERT IGNORE INTO institution (iname) VALUES ('{$institute}')");
$db->query("INSERT IGNORE INTO skills (sname) VALUES ('{$skill}')");
$db->query("INSERT IGNORE INTO cities (cname) VALUES ('{$city}')");
$db->query(
"INSERT IGNORE INTO relation (icode, scode, ccode) VALUES (" .
"(SELECT icode FROM institution WHERE iname = '{$institute}'), " .
"(SELECT scode FROM skills WHERE sname = '{$skill}'), " .
"(SELECT ccode FROM cities WHERE cname = '{$city}'))"
);
}
$db->close();
注意:以上脚本是示例目的。使用批处理模式 或禁用自动提交 对我没有用。因为很多时候我需要向关系表添加单个新记录(基于用户通过网络面板的请求)
经过一些研究和基准测试后,我创建了一个 MySQL 存储函数来加速这个过程,并将性能提高了 250 - 300%
请在这里查看功能:
DELIMITER $$
CREATE FUNCTION courses.record(i_name VARCHAR(255), s_name VARCHAR(255), c_name VARCHAR(255)) RETURNS INT
BEGIN
DECLARE _icode, _scode, _ccode INT UNSIGNED;
SELECT icode INTO _icode FROM institution WHERE iname = i_name;
SELECT scode INTO _scode FROM skills WHERE sname = s_name;
SELECT ccode INTO _ccode FROM cities WHERE cname = c_name;
IF _icode IS NULL THEN
INSERT IGNORE INTO institution (iname) VALUES (i_name);
SELECT icode INTO _icode FROM institution WHERE iname = i_name;
END IF;
IF _scode IS NULL THEN
INSERT IGNORE INTO skills (sname) VALUES (s_name);
SELECT scode INTO _scode FROM skills WHERE sname = s_name;
END IF;
IF _ccode IS NULL THEN
INSERT IGNORE INTO cities (cname) VALUES (c_name);
SELECT ccode INTO _ccode FROM cities WHERE cname = c_name;
END IF;
INSERT IGNORE INTO relation (icode, scode, ccode) VALUES (_icode, _scode, _ccode);
RETURN ROW_COUNT();
END $$
DELIMITER ;
现在,下面这个 PHP 脚本可以通过一次查询在关系表中插入一条记录
<?php
$db = new mysqli('localhost', 'user', '***', 'courses');
$records = [
['ABC Learners', 'CSS', 'Bangalore'],
['ABC Learners', 'PHP', 'Bangalore'],
['ABC Learners', 'HTML', 'Bangalore'],
['ABC Learners', 'PHP', 'Hyderabad'],
['XYZ Solutions', 'PHP', 'Hyderabad'],
['XYZ Solutions', 'JAVA', 'Hyderabad'],
['XYZ Solutions', 'JAVA', 'Bangalore'],
];
$query = $db->prepare("SELECT record (?, ?, ?)");
$query->bind_param('sss', $institute, $skill, $city);
foreach ($records as $record) {
list($institute, $skill, $city) = $record;
$query->execute();
}
$db->close();
This MySQL stored function increased the performance. But, still I'm using multiple INSERT and SELECT statements in this function. Is it possible to optimize this function with few statements to gain more performance?
最佳答案
<强>1。将 UNIQUE 更改为 PRIMARY key:
在没有明确定义主键的情况下,InnoDB 将为每一行创建自己的隐藏主键。但在您的情况下,在表 relation 中,当前 UNIQUE 键更适合定义为 PRIMARY 键( NOT NULL 并满足唯一性)。因此,请将其更改为 PRIMARY KEY。
<强>2。利用批量插入/选择:
通过使用批量插入和选择,并利用一些应用程序捕获,我们基本上可以将其整体分解为 4 个插入和 3 个选择。检查下面的代码(带注释):
$records = [
['ABC Learners', 'CSS', 'Bangalore'],
['ABC Learners', 'PHP', 'Bangalore'],
['ABC Learners', 'HTML', 'Bangalore'],
['ABC Learners', 'PHP', 'Hyderabad'],
['XYZ Solutions', 'PHP', 'Hyderabad'],
['XYZ Solutions', 'JAVA', 'Hyderabad'],
['XYZ Solutions', 'JAVA', 'Bangalore'],
];
// Create a copy of records to avoid changing the original
$records_copy = $records;
// Get unique institutions, skills and cities
$i = array_unique(array_map('array_shift', $records_copy));
$s = array_unique(array_map('array_shift', $records_copy));
$c = array_unique(array_map('array_shift', $records_copy));
// Prepare batch insert and select SQL for institution table
$i_ins_sql = "INSERT IGNORE INTO institution (iname) VALUES ";
$i_sel_sql = "SELECT icode, iname FROM institution WHERE iname IN (";
foreach ($i as $v) {
$i_ins_sql .= "('" . $db->real_escape_string($v) . "'),";
$i_sel_sql .= "'" . $db->real_escape_string($v) . "',";
}
// Execute the INSERT query
$db->query( rtrim($i_ins_sql, ',') );
// Execute the SELECT query and fetch the query result and store (cache) it
// Key of the cache array would be name (string) and the value would be
// the code (integer)
$i_cache = array();
$i_sel_q = $db->query( rtrim($i_sel_sql, ',') . ")" );
while ( $row = $i_sel_q->fetch_assoc() ) {
$i_cache[$row['iname']] = $row['icode'];
}
/**
* REPEAT the INSERT and SELECT steps for the skills and cities tables,
* using $s and $c arrays respectively, with appropriate field names
* Eventually, you would have cache arrays, $s_cache and $c_cache.
**/
// Now let's do a batch INSERT INTO relation table
$sql = "INSERT IGNORE INTO relation (icode, scode, ccode) VALUES ";
// Loop over original records array
foreach ($records as $record) {
$sql .= "(" . (int)$i_cache[$record[0]] . ","
. (int)$i_cache[$record[1]] . ","
. (int)$i_cache[$record[2]] . "),";
}
// Execute the Batch INSERT query into relation table
$db->query( rtrim($sql, ',') );
最后但同样重要的是:您的代码对 SQL injection 开放相关攻击。连real_escape_string不能完全保护它。请学会使用Prepared Statements相反。
关于php - 每次向依赖 FOREIGN KEY 的 MySQL 表插入数据时,是否需要每次执行额外的 SELECT 和 INSERT IGNORE 查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57569008/
我在使用omniauth/openid时遇到了一些麻烦。在尝试进行身份验证时,我在日志中发现了这一点:OpenID::FetchingError:Errorfetchinghttps://www.google.com/accounts/o8/.well-known/host-meta?hd=profiles.google.com%2Fmy_username:undefinedmethod`io'fornil:NilClass重要的是undefinedmethodio'fornil:NilClass来自openid/fetchers.rb,在下面的代码片段中:moduleNetclass
我遵循了教程http://gettingstartedwithchef.com/,第1章。我的运行list是"run_list":["recipe[apt]","recipe[phpap]"]我的phpapRecipe默认Recipeinclude_recipe"apache2"include_recipe"build-essential"include_recipe"openssl"include_recipe"mysql::client"include_recipe"mysql::server"include_recipe"php"include_recipe"php::modul
我正在尝试修改当前依赖于定义为activeresource的gem:s.add_dependency"activeresource","~>3.0"为了让gem与Rails4一起工作,我需要扩展依赖关系以与activeresource的版本3或4一起工作。我不想简单地添加以下内容,因为它可能会在以后引起问题:s.add_dependency"activeresource",">=3.0"有没有办法指定可接受版本的列表?~>3.0还是~>4.0? 最佳答案 根据thedocumentation,如果你想要3到4之间的所有版本,你可以这
关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion在首页我有:汽车:VolvoSaabMercedesAudistatic_pages_spec.rb中的测试代码:it"shouldhavetherightselect"dovisithome_pathit{shouldhave_select('cars',:options=>['volvo','saab','mercedes','audi'])}end响应是rspec./spec/request
我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("
我是Google云的新手,我正在尝试对其进行首次部署。我的第一个部署是RubyonRails项目。我基本上是在关注thisguideinthegoogleclouddocumentation.唯一的区别是我使用的是我自己的项目,而不是他们提供的“helloworld”项目。这是我的app.yaml文件runtime:customvm:trueentrypoint:bundleexecrackup-p8080-Eproductionconfig.ruresources:cpu:0.5memory_gb:1.3disk_size_gb:10当我转到我的项目目录并运行gcloudprevie
我在用Ruby执行简单任务时遇到了一件奇怪的事情。我只想用每个方法迭代字母表,但迭代在执行中先进行:alfawit=("a".."z")puts"That'sanalphabet:\n\n#{alfawit.each{|litera|putslitera}}"这段代码的结果是:(缩写)abc⋮xyzThat'sanalphabet:a..z知道为什么它会这样工作或者我做错了什么吗?提前致谢。 最佳答案 因为您的each调用被插入到在固定字符串之前执行的字符串文字中。此外,each返回一个Enumerable,实际上您甚至打印它。试试
如何检查Ruby文件是否是通过“require”或“load”导入的,而不是简单地从命令行执行的?例如:foo.rb的内容:puts"Hello"bar.rb的内容require'foo'输出:$./foo.rbHello$./bar.rbHello基本上,我想调用bar.rb以不执行puts调用。 最佳答案 将foo.rb改为:if__FILE__==$0puts"Hello"end检查__FILE__-当前ruby文件的名称-与$0-正在运行的脚本的名称。 关于ruby-检查是否
文章目录一、概述简介原理模块二、配置Mysql使用版本环境要求1.操作系统2.mysql要求三、配置canal-server离线下载在线下载上传解压修改配置单机配置集群配置分库分表配置1.修改全局配置2.实例配置垂直分库水平分库3.修改group-instance.xml4.启动监听四、配置canal-adapter1修改启动配置2配置映射文件3启动ES数据同步查询所有订阅同步数据同步开关启动4.验证五、配置canal-admin一、概述简介canal是Alibaba旗下的一款开源项目,Java开发。基于数据库增量日志解析,提供增量数据订阅&消费。Git地址:https://github.co
//1.验证返回状态码是否是200pm.test("Statuscodeis200",function(){pm.response.to.have.status(200);});//2.验证返回body内是否含有某个值pm.test("Bodymatchesstring",function(){pm.expect(pm.response.text()).to.include("string_you_want_to_search");});//3.验证某个返回值是否是100pm.test("Yourtestname",function(){varjsonData=pm.response.json