在阅读公司原来代码的过程当中,我发现了这样一段代码:php
$sql = "INSERT INTO {$table} ({$fields}) VALUES " . $values; if (!empty($onDuplicate)) { $sql .= ' ON DUPLICATE KEY UPDATE '. $onDuplicate; }
在语义的理解上,应当是索引冲突则更新原有索引数据。通过查阅资料,我总结以下:mysql
假设业务上咱们须要的就是若是存在则更新,若是不存在则新增. INSERT 中ON DUPLICATE KEY UPDATE(用redis的kv就能够很容易的实现.在MySQL中也有这样的功能)redis
可是这个在在使用的时候须要把关键的字段(列)设置为key ,unique key。(也就是会发生冲突的索引)sql
若是您指定了ON DUPLICATE KEY UPDATE,而且插入行后会致使在一个UNIQUE索引或PRIMARY KEY中出现重复值,则执行旧行UPDATE。docker
CREATE TABLE `test_duplicate` ( `id` int(11) NOT NULL AUTO_INCREMENT, `a` int(11) NOT NULL, `b` int(11) NOT NULL, `c` int(11) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `a` (`a`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; insert into test_duplicate (a,b,c) values(1,2,3);
假设咱们有表如上,SQL列a被定义为UNIQUE,而且包含值1,则如下两段语句具备相同的效果:数据库
mysql>INSERT INTO test_duplicate (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE c=c+1; mysql> select * from test_duplicate; +----+---+---+---+ | id | a | b | c | +----+---+---+---+ | 1 | 1 | 2 | 4 | +----+---+---+---+ mysql>SELECT id,a,b,c from test_duplicate where a=1; mysql>UPDATE table SET c=c+1 WHERE id=1; SELECT id,a,b,c from test_duplicate where a=1; +----+---+---+---+ | id | a | b | c | +----+---+---+---+ | 1 | 1 | 2 | 5 | +----+---+---+---+
从结果能够看出来,2段SQL都都c进行了+1操做。可是insert实际上并无进行插入数据而是进行了更新数据。服务器
那若是,咱们表内有两个可能会产生冲突的键时,又会如何呢?session
mysql> ALTER TABLE `test_duplicate` ADD UNIQUE(`b`); mysql> INSERT INTO test_duplicate (a,b,c) VALUES (2,3,4); mysql> INSERT INTO test_duplicate (a,b,c) VALUES (1,3,4) ON DUPLICATE KEY UPDATE c=c+1; Query OK, 2 rows affected (0.00 sec) mysql> select * from test_duplicate; +----+---+---+---+ | id | a | b | c | +----+---+---+---+ | 1 | 1 | 2 | 6 | | 3 | 2 | 3 | 4 | +----+---+---+---+
能够看出来,同时更新了两条数据 。php7
那假如同一行数据,咱们有两个冲突的值会产生怎么样的结果呢?函数
mysql> INSERT INTO test_duplicate (a,b,c) VALUES (1,2,4) ON DUPLICATE KEY UPDATE c=c+1; mysql> select * from test_duplicate; +----+---+---+---+ | id | a | b | c | +----+---+---+---+ | 1 | 1 | 2 | 7 | | 3 | 2 | 3 | 4 | +----+---+---+---+
所以,咱们在设计表的时候,应该尽可能避免多冲突值得存在,若是实在避免不了,咱们能够使用values方法获取本次提交的值。VALUES()函数只在INSERT...UPDATE语句中有意义,其它时候会返回NULL。
mysql> INSERT INTO test_duplicate (a,b,c) VALUES (1,2,4) ON DUPLICATE KEY UPDATE c=values(c); mysql> select * from test_duplicate; +----+---+---+---+ | id | a | b | c | +----+---+---+---+ | 1 | 1 | 2 | 4 | | 3 | 2 | 3 | 4 | +----+---+---+---+
应该通常需求都是要达到这个结果
须要注意的是,在事务中,只有SELECT ... FOR UPDATE 或LOCK IN SHARE MODE 同一笔数据时会等待其它事务结束后才执行,通常SELECT ... 则不受此影响。拿上面的实例来讲,当我执行select status from t_goods where id=1 for update;后。我在另外的事务中若是再次执行select status from t_goods where id=1 for update;则第二个事务会一直等待第一个事务的提交,此时第二个查询处于阻塞的状态,可是若是我是在第二个事务中执行select status from t_goods where id=1;则能正常查询出数据,不会受第一个事务的影响。
刚入职的时候,我编译了本身的docker是php7环境的,而后没法支持mysql只支持mysqlnd做为pdo驱动。因而乎,错误来了
"SQLSTATE[HY000] [2000] mysqlnd cannot connect to MySQL 4.1+ using the old insecure authentication. Please use an administration tool to reset your password with the command SET PASSWORD = PASSWORD('your_existing_password'). This will store a new, and more secure, hash value in mysql.user. If this user is used in other scripts executed by PHP 5.2 or earlier you might need to remove the old-passwords flag from your my.cnf file
在google遨游了好久,也没找到解决方式,而后,也尝试着装mysql而后编译PHP的时候使用mysql的头文件尝试修改mysqlnd的方式也没有成功。
网上大部分答案都须要登入mysql服务器去改my.cnf。
最后终于搞定了,将他记录下来,原来能够临时修改会话的密码长度而后重设。
mysql> SELECT user, Length(`Password`) FROM `mysql`.`user`; +----------------+--------------------+ | user | Length(`Password`) | +----------------+--------------------+ | root | 16 | | root | 0 | | root | 0 | | | 0 | | | 0 | | root | 16 | | test | 16 | | club_star_user | 16 | | club_star_user | 16 | | wenlong11 | 16 | +----------------+--------------------+
mysql> SET SESSION old_passwords = 0; Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @@global.old_passwords, @@session.old_passwords, Length(PASSWORD('abc'));
mysql> UPDATE mysql.user SET Password = PASSWORD('123456') WHERE user = 'xxxx'; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> flush privileges; Query OK, 0 rows affected (0.00 sec) mysql> SELECT user, Length(`Password`) FROM `mysql`.`user`; +----------------+--------------------+ | user | Length(`Password`) | +----------------+--------------------+ | root | 16 | | root | 0 | | root | 0 | | | 0 | | | 0 | | root | 16 | | test | 16 | | club_star_user | 16 | | club_star_user | 16 | | wenlong11 | 41 | +----------------+--------------------+
能够观察到 密码长度终于变成41的新版的长度了
mysql排序 假如对不少值相等的值进行order 分页 会产生乱序 致使数据重复
select * from where a = 3 and b = 5 order by c desc select * from where a = 3 and b =5 order by c desc, d desc
解决方式: 一、尽可能不要使用这种字段排序 二、若是业务需求,将其修改为多种混合 如 order field desc => order field desc, uniqueField desc 确保结果不会混乱
示例: explain select * from tablename;
将会得出结果查询详情,而不是结果集
expain出来的信息有10列,分别是id、select_type、table、type、possible_keys、key、key_len、ref、rows、Extra
在某些状况下,mysql推荐的索引并非咱们最想用的业务(根据业务需求)
这个时候,咱们能够将本身肯定的索引进行设置,保证本条SQL强制走索引
select * from $table_name force index(index_name) where condition limit number
8000W 数据,不用force index 200s都未查询完毕
加了以后,1S左右完成
执行explain,发现这个sql扫描了8000W条记录到磁盘上。而后再进行筛选。type=index说明整个索引树都被扫描了,效果显然不理想。
对应的,在某些状况下咱们肯定了不须要某个索引
这个时候,咱们能够将此索引忽略,保证本条SQL不遍历这个索引