可以使用MySQL FIND_IN_SET或等价物来使用索引吗?
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了可以使用MySQL FIND_IN_SET或等价物来使用索引吗?,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含4561字,纯文字阅读大概需要7分钟。
内容图文
如果我比较
explain select * from Foo where find_in_set(id,'2,3');
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | User | ALL | NULL | NULL | NULL | NULL | 4 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
用这个
explain select * from Foo where id in (2,3);
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| 1 | SIMPLE | User | range | PRIMARY | PRIMARY | 8 | NULL | 2 | Using where |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
很明显,FIND_IN_SET不利用主键.
我想将一个如上所述的查询放入存储过程中,并以逗号分隔的字符串作为参数.
是否有任何方法可以使查询的行为类似于使用索引的第二个版本,但不知道在编写查询时设置的id的内容?
解决方法:
参考你的评论:
@MarcB the database is normalized, the CSV string comes from the UI.
“Get me data for the following people: 101,202,303”
这个答案只关注那些用逗号分隔的数字.因为事实证明,你甚至都没有谈论过FIND_IN_SET.
是的,你可以实现你想要的.您创建一个准备好的语句,接受一个字符串作为参数,就像在我的这个Recent Answer中一样.在该答案中,查看显示CREATE PROCEDURE的第二个块及其接受类似(1,2,3)的字符串的第二个参数.我马上就会回到这一点.
不是你需要看到它@spraff但其他人可能.任务是获取类型!= ALL,并且Explain的possible_keys和键不显示null,如您在第二个块中所示.有关该主题的一般性阅读,请参阅文章Understanding EXPLAIN’s Output和名为EXPLAIN Extra Information的MySQL手册页.
现在,回到上面的(1,2,3)参考.我们从您的评论中了解到,并且您在问题中的第二个解释输出符合以下所需条件:
> type = range(特别是不是ALL).请参阅上面的文档.
> key不为null
这些正是您在第二个Explain输出中的条件,以及可通过以下查询看到的输出:
explain
select * from ratings where id in (2331425, 430364, 4557546, 2696638, 4510549, 362832, 2382514, 1424071, 4672814, 291859, 1540849, 2128670, 1320803, 218006, 1827619, 3784075, 4037520, 4135373, ... use your imagination ..., ..., 4369522, 3312835);
其中我在子句列表中有999个值.这是我在附录D中从this answer开始的样本比生成这样一个随机的csv字符串,由开括号和近括号括起来.
请注意下面的999元素的以下说明输出:
目标实现.你可以使用类似于我之前在this link中使用PREPARED STATEMENT提到的存储过程实现这一点(那些东西使用concat()后跟一个EXECUTE).
使用索引,没有经历Tablescan(意思是坏).进一步的读数是The range Join Type,您可以在MySQL的基于成本的优化器(CBO)上找到任何参考,这个answer来自vladr,但注明ANALYZE TABLE部分,特别是在重大数据更改之后.请注意,ANALYZE可能需要花费大量时间才能在超大型数据集上运行.有时候很多个小时.
Sql注入攻击:
使用传递给存储过程的字符串是SQL注入攻击的攻击媒介.在使用用户提供的数据时,必须采取预防措施以防止它们发生.如果您的例程适用于您自己的系统生成的id,那么您就是安全的.但请注意,当数据由先前插入或更新中未清理该数据的例程放置到位时,会发生第二级SQL注入攻击.攻击通过数据预先存在并在以后使用(一种定时炸弹).
所以这个答案大部分都是完成的.
下面是对同一个表的一个视图,对它进行了一些小的修改,以显示在先前的查询中可怕的Tablescan的样子(但是对于一个名为thing的非索引列).
看看我们当前的表定义:
CREATE TABLE `ratings` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`thing` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5046214 DEFAULT CHARSET=utf8;
select min(id), max(id),count(*) as theCount from ratings;
+---------+---------+----------+
| min(id) | max(id) | theCount |
+---------+---------+----------+
| 1 | 5046213 | 4718592 |
+---------+---------+----------+
请注意,列事物之前是可以为空的int列.
update ratings set thing=id where id<1000000;
update ratings set thing=id where id>=1000000 and id<2000000;
update ratings set thing=id where id>=2000000 and id<3000000;
update ratings set thing=id where id>=3000000 and id<4000000;
update ratings set thing=id where id>=4000000 and id<5100000;
select count(*) from ratings where thing!=id;
-- 0 rows
ALTER TABLE ratings MODIFY COLUMN thing int not null;
-- current table definition (after above ALTER):
CREATE TABLE `ratings` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`thing` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5046214 DEFAULT CHARSET=utf8;
然后解释是一个Tablescan(针对列事):
内容总结
以上是互联网集市为您收集整理的可以使用MySQL FIND_IN_SET或等价物来使用索引吗?全部内容,希望文章能够帮你解决可以使用MySQL FIND_IN_SET或等价物来使用索引吗?所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。