Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/267.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 e外部结果如下: (SELECT ... LIMIT 1) UNION (SELECT ... LIMIT 1) UNION (SELECT ... LIMIT 1) ... UNION (SELECT ... LIMIT 1) LIMIT 3_Php_Mysql_Performance_Random - Fatal编程技术网

Php e外部结果如下: (SELECT ... LIMIT 1) UNION (SELECT ... LIMIT 1) UNION (SELECT ... LIMIT 1) ... UNION (SELECT ... LIMIT 1) LIMIT 3

Php e外部结果如下: (SELECT ... LIMIT 1) UNION (SELECT ... LIMIT 1) UNION (SELECT ... LIMIT 1) ... UNION (SELECT ... LIMIT 1) LIMIT 3,php,mysql,performance,random,Php,Mysql,Performance,Random,不过,仍然不能保证将获取3行。这只会使它更有可能出现。创建另一个只包含带有图像的项的表怎么样?这张桌子会更轻,因为它只包含原始桌子的三分之一的物品 ------------------------------------------ |ID | Item ID (on the original table)| ------------------------------------------ |0 | 0 | ----

不过,仍然不能保证将获取3行。这只会使它更有可能出现。

创建另一个只包含带有图像的项的表怎么样?这张桌子会更轻,因为它只包含原始桌子的三分之一的物品

------------------------------------------
|ID     | Item ID (on the original table)|
------------------------------------------
|0      | 0                              |
------------------------------------------
|1      | 123                            |
------------------------------------------
            .
            .
            .
------------------------------------------
|10 000 | 30 000                         |
------------------------------------------

然后,您可以在代码的PHP部分生成三个随机ID,并从数据库中获取它们。

如果您愿意接受“开箱即用”类型的答案,我将重复我在一些注释中所说的内容

SELECT COUNT(ID)
INTO @count
FROM Products
WHERE HasImages = 1;

PREPARE random_records FROM
'(
    SELECT * FROM Products WHERE HasImages = 1 LIMIT ?, 1
) UNION (
    SELECT * FROM Products WHERE HasImages = 1 LIMIT ?, 1
) UNION (
    SELECT * FROM Products WHERE HasImages = 1 LIMIT ?, 1
)';

SET @l1 = ROUND(RAND() * @count);
SET @l2 = ROUND(RAND() * @count);
SET @l3 = ROUND(RAND() * @count);

EXECUTE random_records USING @l1
    , @l2
    , @l3;
DEALLOCATE PREPARE random_records;
SELECT COUNT(ID)
INTO @count
FROM Products
WHERE HasImages = 1;

PREPARE random_records FROM
'SELECT * FROM Products WHERE HasImages = 1 LIMIT ?, 1';

SET @l1 = ROUND(RAND() * @count);
SET @l2 = ROUND(RAND() * @count);
SET @l3 = ROUND(RAND() * @count);

EXECUTE random_records USING @l1;
EXECUTE random_records USING @l2;
EXECUTE random_records USING @l3;

DEALLOCATE PREPARE random_records;
解决问题的最佳方法是提前缓存数据(可以是外部JSON或XML文件,也可以是单独的数据库表,甚至可能是内存表)

通过这种方式,您可以将产品表上的性能影响安排在您知道服务器将处于安静状态的时间,并减少您对在访问者到达您的站点时“随机”创建性能影响的担忧



我不会建议一个明确的解决方案,因为关于如何构建一个解决方案有太多的可能性。然而,@ahmed提出的答案并不愚蠢。如果您不想在查询中创建联接,只需将所需的更多数据加载到新表中即可。

这不是您想要的解决方案,但为了提高性能,您可以让cronjob每5分钟选择3个随机产品,并将其缓存在文件中,然后将该文件包含在页面中。哦,我明白了。如果需要8秒,这意味着可能没有索引。一次完整的表扫描不会花费那么长的时间进行行计数。如果在php中获得3个随机ID,然后获取具有此ID的行,可能会更快?我倾向于同意@Sumurai8。与其在每一个新的请求中都对产品列表表进行重击,然后抱怨性能,不如将随机选择预加载到文件或辅助表中。您可以预先获取20或100个组合(可能每小时/每天更新),然后从这些选项中随机选择。解决方案III的测试结果:我没有检索随机结果。我将前10000行设置为HasImages=0(id 1到10000),并将20000行设置为HasImages=1(id 10001到30000)。我从来没有收到id超过15000的结果。我会认真测试它。我在Debian Squence(mysqld版本5.1.63-0+squeeze1日志)上运行它,需要0.18秒。使用“16”因子近似值作为基准,“从HasImages=1 ORDER BY RAND()LIMIT 3的产品中选择*”;在我的机器上需要28毫秒,这意味着上述语句快了约33%。正如@Anthony之前提到的那样,您的表/mysql可能有问题。我的意思是,您在我的服务器上的解决方案需要0.18秒,解决方案III带有“从产品中选择Products.ID、Products.Name,其中((Products.Hasimages=1)和RAND()<16*3/30000)LIMIT 3;”意味着查询获取了3条连续记录。我测试了您的解决方案,它总是获得连续的ID值,例如:104851048710488。ID=10486被过滤掉,因为相应的产品没有可用的图像,即HasImages=0。我在Linux上测试过,它给出了0.10到0.20s的值。最后只有一张唱片。我不知道我在想什么,对不起。我已经更新了我的答案,我希望这是您正在寻找的答案。我测试了您的第一个解决方案,添加了WHERE子句:它只得到0,1,2条记录,3是罕见的。您是否也向first
SELECT COUNT(ID)
query添加了条件?向SELECT COUNT(ID)添加WHERE子句将不会有任何效果,因为l1,l2,l3不保证行满足HasImages=1条件。此解决方案可确保一个随机行的3倍。缺点是三个ID在数学上可能相同,例如10088、10088、10088。但这在现实世界中可能永远不会发生。它占用CPU 0.01到0.20秒。@jacouh您在
(HasImages)
上有索引吗?这应该比0.20秒快得多。@ypercube,是的,这个表有PK.ID,并且.HasImages也被索引。我刚刚测试了这个方法,并且经常收到一条特定的记录(HasImages=1的最低ID产品)。如果我将筛选器更改为HasImages=0,则大多数情况下我不会收到3行。@OmniPotens我扩展了帖子,请查看。如果您的MySQLd安装在功能非常强大的计算机中,这样它就可以忽略进行连接所需的工作,那么这将是一个好主意:SELECT Products.ID,Products.Name FROM Products INNER JOIN tblIdsHasImages ON Products.ID=tblIdsHasImages.ItemID;对于一般的服务器来说,这项额外的工作是相当大的,它可能会导致CPU卡滞。将所有字段产品复制到tblIdsHasImages是个坏主意。@jacouh真的吗?您认为数据库引擎对
UNION
3个查询所做的工作量小于将PK连接到FK所需的工作量吗?我愿意打赌不是这样。使用查询随机选择可以添加其他条件,例如加入产品的原产国表、宗教相关信息表等。。。相对静态的缓存方法很难覆盖这一点。@jacouh再次强调,这取决于您如何设计缓存。信息技术
SELECT Products.ID, Products.Name
FROM Products
INNER JOIN (SELECT (RAND() * (SELECT MAX(ID) FROM Products)) AS ID) AS t ON Products.ID     >= t.ID
WHERE (Products.HasImages=1)
ORDER BY Products.ID ASC
LIMIT 3;
SELECT Products.ID, Products.Name
FROM Products
INNER JOIN (SELECT (ROUND((RAND() * (max-min))+min)) AS ID) AS t ON Products.ID     >= t.ID
WHERE (Products.HasImages=1)
ORDER BY Products.ID ASC
LIMIT 3;
max = select max(id)
min = 225
SELECT COUNT(ID)
INTO @count
FROM Products
WHERE HasImages = 1;

PREPARE random_records FROM
'(
    SELECT * FROM Products WHERE HasImages = 1 LIMIT ?, 1
) UNION (
    SELECT * FROM Products WHERE HasImages = 1 LIMIT ?, 1
) UNION (
    SELECT * FROM Products WHERE HasImages = 1 LIMIT ?, 1
)';

SET @l1 = ROUND(RAND() * @count);
SET @l2 = ROUND(RAND() * @count);
SET @l3 = ROUND(RAND() * @count);

EXECUTE random_records USING @l1
    , @l2
    , @l3;
DEALLOCATE PREPARE random_records;
SELECT COUNT(ID)
INTO @count
FROM Products
WHERE HasImages = 1;

PREPARE random_records FROM
'SELECT * FROM Products WHERE HasImages = 1 LIMIT ?, 1';

SET @l1 = ROUND(RAND() * @count);
SET @l2 = ROUND(RAND() * @count);
SET @l3 = ROUND(RAND() * @count);

EXECUTE random_records USING @l1;
EXECUTE random_records USING @l2;
EXECUTE random_records USING @l3;

DEALLOCATE PREPARE random_records;
(SELECT Products.ID, Products.Name
FROM Products
    INNER JOIN (SELECT RAND()*(SELECT MAX(ID) FROM Products) AS ID) AS t ON Products.ID >= t.ID
WHERE Products.HasImages=1
ORDER BY Products.ID
LIMIT 1)

UNION ALL

(SELECT Products.ID, Products.Name
FROM Products
    INNER JOIN (SELECT RAND()*(SELECT MAX(ID) FROM Products) AS ID) AS t ON Products.ID >= t.ID
WHERE Products.HasImages=1
ORDER BY Products.ID
LIMIT 1)

UNION ALL

(SELECT Products.ID, Products.Name
FROM Products
    INNER JOIN (SELECT RAND()*(SELECT MAX(ID) FROM Products) AS ID) AS t ON Products.ID >= t.ID
WHERE Products.HasImages=1
ORDER BY Products.ID
LIMIT 1)
(SELECT ... LIMIT 1)
UNION (SELECT ... LIMIT 1)
UNION (SELECT ... LIMIT 1)
...
UNION (SELECT ... LIMIT 1)
LIMIT 3
------------------------------------------
|ID     | Item ID (on the original table)|
------------------------------------------
|0      | 0                              |
------------------------------------------
|1      | 123                            |
------------------------------------------
            .
            .
            .
------------------------------------------
|10 000 | 30 000                         |
------------------------------------------