Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php MySQL Query IN()子句在索引列上运行缓慢_Php_Mysql_Performance - Fatal编程技术网

Php MySQL Query IN()子句在索引列上运行缓慢

Php MySQL Query IN()子句在索引列上运行缓慢,php,mysql,performance,Php,Mysql,Performance,我有一个由PHP脚本生成的MySQL查询,查询如下所示: SELECT * FROM Recipe_Data WHERE 404_Without_200 = 0 AND Failures_Without_Success = 0 AND RHD_No IN (10, 24, 34, 41, 43, 51, 57, 59, 61, 67, 84, 90, 272, 324, 402, 405, 414, 498, 500, 501, 510, 559, 562, 595, 632, 634, 640

我有一个由PHP脚本生成的MySQL查询,查询如下所示:

SELECT * FROM Recipe_Data WHERE 404_Without_200 = 0 AND Failures_Without_Success = 0 AND RHD_No IN (10, 24, 34, 41, 43, 51, 57, 59, 61, 67, 84, 90, 272, 324, 402, 405, 414, 498, 500, 501, 510, 559, 562, 595, 632, 634, 640, 643, 647, 651, 703, 714, 719, 762, 765, 776, 796, 812, 814, 815, 822, 848, 853, 855, 858, 866, 891, 920, 947, 956, 962, 968, 1049, 1054, 1064, 1065, 1070, 1100, 1113, 1119, 1130, 1262, 1287, 1292, 1313, 1320, 1327, 1332, 1333, 1335, 1340, 1343, 1344, 1346, 1349, 1352, 1358, 1362, 1365, 1482, 1495, 1532, 1533, 1537, 1549, 1550, 1569, 1571, 1573, 1574, 1596, 1628, 1691, 1714, 1720, 1735, 1755, 1759, 1829, 1837, 1844, 1881, 1919, 2005, 2022, 2034, 2035, 2039, 2054, 2076, 2079, 2087, 2088, 2089, 2090, 2091, 2092, 2154, 2155, 2156, 2157, 2160, 2162, 2164, 2166, 2169, 2171, 2174, 2176, 2178, 2179, 2183, 2185, 2186, 2187, 2201, 2234, 2236, 2244, 2245, 2250, 2255, 2260, 2272, 2280, 2281, 2282, 2291, 2329, 2357, 2375, 2444, 2451, 2452, 2453, 2454, 2456, 2457, 2460, 2462, 2464, 2465, 2467, 2468, 2469, 2470, 2473, 2474, 2481, 2485, 2487, 2510, 2516, 2519, 2525, 2540, 2545, 2547, 2553, 2571, 2579, 2580, 2587, 2589, 2597, 2602, 2611, 2629, 2660, 2662, 2700, 2756, 2825, 2833, 2835, 2858, 2958, 2963, 2964, 3009, 3090, 3117, 3118, 3120, 3121, 3122, 3123, 3126, 3127, 3129, 3130, 3133, 3135, 3137, 3138, 3139, 3141, 3142, 3145, 3146, 3147, 3151, 3152, 3155, 3193, 3201, 3204, 3219, 3221, 3222, 3223, 3224, 3225, 3226, 3227, 3228, 3229, 3231, 3232, 3233, 3234, 3235, 3237, 3239, 3246, 3250, 3253, 3259, 3261, 3291, 3315, 3328, 3377, 3381, 3383, 3384, 3385, 3387, 3388, 3389, 3390, 3396, 3436, 3463, 3465, 3467, 3470, 3471, 3484, 3507, 3515, 3554, 3572, 3641, 3672, 3683, 3689, 3690, 3692, 3693, 3694, 3697, 3698, 3705, 3711, 3713, 3715, 3716, 3717, 3719, 3720, 3722, 3726, 3727, 3732, 3737, 3763, 3767, 3770, 3771, 3772, 3773, 3803, 3810, 3812, 3816, 3846, 3847, 3848, 3851, 3874, 3882, 3902, 3903, 3906, 3908, 3916, 3924, 3967, 3987, 4006, 4030, 4043, 4045, 4047, 4058, 4067, 4107, 4108, 4114, 4115, 4131, 4132, 4133, 4137, 4138, 4139, 4140, 4141, 4142, 4146, 4150, 4151, 4152, 4153, 4157, 4158, 4160, 4163, 4166, 4167, 4171, 4179, 4183, 4221, 4225, 4242, 4257, 4435, 4437, 4438, 4443, 4446, 4449, 4450, 4451, 4452, 4454, 4460, 4550, 4557, 4618, 4731, 4775, 4804, 4972, 5025, 5026, 5039, 5042, 5294, 5578, 5580, 5599, 5602, 5649, 5726, 5779, 5783, 5931, 5934, 5936, 5939, 5940, 5941, 5978, 6044, 6056, 6113, 6116, 6118, 6122, 6123, 6125, 6127, 6128, 6129, 6130, 6131, 6135, 6141, 6145, 6147, 6150, 6152, 6153, 6154, 6160, 6166, 6169);
列RHD_No是该数据库的主键,总共约有400000行。问题是,查询速度非常慢,通常约为2秒,但我看到它长达10秒

当我试图解释这个问题时,一切似乎都应该是好的:

+----+-------------+-------------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table       | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+----+-------------+-------------+-------+---------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | Recipe_Data | range | PRIMARY       | PRIMARY | 4       | NULL |  420 | Using where |
+----+-------------+-------------+-------+---------------+---------+---------+------+------+-------------+
当我分析查询时,我得到:

mysql> show profile;
+--------------------------------+----------+
| Status                         | Duration |
+--------------------------------+----------+
| starting                       | 0.000015 |
| checking query cache for query | 0.000266 |
| Opening tables                 | 0.000009 |
| System lock                    | 0.000004 |
| Table lock                     | 0.000006 |
| init                           | 0.000115 |
| optimizing                     | 0.000038 |
| statistics                     | 0.000797 |
| preparing                      | 0.000047 |
| executing                      | 0.000002 |
| Sending data                   | 2.675270 |
| end                            | 0.000007 |
| query end                      | 0.000003 |
| freeing items                  | 0.000071 |
| logging slow query             | 0.000002 |
| logging slow query             | 0.000058 |
| cleaning up                    | 0.000005 |
+--------------------------------+----------+

我一直在研究这个问题很长一段时间,我还没有找到解决办法。这个问题有什么明显的错误吗?我不认为查看420行需要2秒以上的时间

您应该将IN子句转换为内部联接子句

您可以像这样转换查询:

SELECT  foo   
FROM    bar   
WHERE bar.stuff IN  
       (SELECT  stuff FROM asdf)
进入另一个类似的查询:

SELECT  b.foo 
FROM    ( 
        SELECT  DISTINCT stuff 
        FROM    asdf ) a 
JOIN    bar b 
ON      b.stuff = a.stuff
你会得到很多表现


当php生成查询时,尝试一些技巧,比如为IN子句中的项创建临时表。如果可以的话,一定要尽量避免IN子句,因为它们非常耗时。

问题是
IN
基本上被视为一堆
s(例如

这比加入要慢得多

您应该做的是生成创建临时表的SQL代码,用“in”子句中的值填充临时表,然后与临时表联接

CREATE TEMPORARY TABLE numbers (n INT)
然后在循环中,添加

INSERT numbers  VALUES ($next_number)
然后在最后

SELECT * FROM numbers, Recipe_Data 
WHERE numbers.n = RHD_No

您正在通过主键访问420行,这可能会导致索引访问路径。这可能会访问2个索引页,每个键访问一个数据页。如果这些索引页在缓存中,则查询应该运行得很快。如果不在缓存中,则进入磁盘的每个页面访问都将产生通常的磁盘延迟。如果我们假设5毫秒的磁盘延迟和80%的缓存命中率,则达到420*3*0.2*5ms=1.2秒,这取决于您所看到的内容。

我在这里赌一把,并建议只执行一次以下查询以创建适合您的查询的索引,应该将查询时间至少缩短一秒

CREATE INDEX returnstatus ON Recipe_Data(404_Without_200,Failures_Without_Success)
请参阅:有关创建索引以及如何在查询中使用索引的信息

如果失败,请查看mysql上所有正在运行的进程,查看当前正在运行的来自任何源的查询是否在消耗服务器所有时间的同时拒绝终止。请参阅:

如果做不到这一点,请确定每条记录可能还有哪些共同点,以避免在
语句中通过ID号单独引用每条记录。如有必要,请添加另一个表列以跟踪该公共性。然后,添加列与上述索引具有相同之处,并根据
WHERE
子句中的索引进行过滤,而不是使用
in
语句。例如,如果您只想在页面上打印这些ID号,请将
可见的
列作为类型:
tinyint
,值
0
排除,值
1
包含在内lude在搜索结果中,然后将
visible
列添加到索引和
WHERE
子句中,以加快查询速度。在
语句中根本不需要该


可能您的
in
语句是使用以前的查询动态生成的。如果是这种情况,请尝试提取所有包含
Recipe\u数据的行,其中404\u不包含\u 200=0,Failures\u不包含\u Success=0
。然后在PHP脚本中,如果
RHD\u No
与预期值不匹配,只需在fetch循环中丢弃一条记录即可

对于像我这样使用SQlAlchemy的人来说,使用For循环也是一个不错的选择:

rows=[]

for id in ids:
  row = cls.query.filter(cls.id==id).first()
  if row:
     rows.append(row)

#return rows

您是否可以提供一个链接来解释为什么和/或测量in子句比JOIN慢多少?当然:不要忘记在末尾删除temp表,很明显:)我认为类似的
in
子句的性能在不同的服务器之间一定会有很大的差异。这个问题被标记为“mysql”,所以可能这就是您所指的。根据我使用SQL Server 2000/2005的经验,用于主键查找的大型
In
子句非常快(我想到的应用程序中的数据库和查询都经过了高度优化;它们都是高流量、大容量web应用程序中的代码)。@Pointy-可能是特定于服务器的,我知道Sybase在IN中有这种性能行为,至少在较旧的版本(12之前)上是这样的。我还看到过大型
IN
子句的性能问题。MySQL似乎没有像这些子句那样使用索引。是否有多个函数和类似于或(函数中)的函数?那么我该如何改进我的查询?只是一个预感,但是在
Recipe\u Data
上所有的索引都是什么样子的?我有一个主键RHD\u No,在另一列上有一个唯一的键。不是键(本质上),但是索引。我不是mysql专家,所以这不是一个答案,但是您是否尝试过在
404\u上添加索引而不添加200,失败而不添加成功
?有关在查询中的用法和创建索引的信息,请参阅。
CREATE INDEX returnstatus ON Recipe_Data(404_Without_200,Failures_Without_Success)
rows=[]

for id in ids:
  row = cls.query.filter(cls.id==id).first()
  if row:
     rows.append(row)

#return rows