Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/278.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/67.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 计数(id)或最大值(id)-哪个更快?_Php_Mysql_Performance - Fatal编程技术网

Php 计数(id)或最大值(id)-哪个更快?

Php 计数(id)或最大值(id)-哪个更快?,php,mysql,performance,Php,Mysql,Performance,我有一个web服务器,在这个服务器上我实现了自己的消息传递系统。 我正处于需要创建一个API来检查用户是否有新消息的阶段 我的DB表很简单: ID - Auto Increment, Primary Key (Bigint) Sender - Varchar (32) // Foreign Key to UserID hash from Users DB Table Recipient - Varchar (32) // Foreign Key to UserID hash from Users

我有一个web服务器,在这个服务器上我实现了自己的消息传递系统。 我正处于需要创建一个API来检查用户是否有新消息的阶段

我的DB表很简单:

ID - Auto Increment, Primary Key (Bigint)
Sender - Varchar (32) // Foreign Key to UserID hash from Users DB Table
Recipient - Varchar (32) // Foreign Key to UserID hash from Users DB Table
Message - Varchar (256) //UTF8 BIN
我正在考虑制作一个API,用于估计给定用户是否有新消息。我正在考虑使用以下方法之一:

发件人或收件人为我的邮件的Select countID。 如果这个号码>以前的号码,我有一条新消息

B选择发件人或收件人为我的邮件的最大ID。 如果maxID>大于上一个数字,则我有一条新消息

我的问题是:我能计算出哪种方法会消耗更少的服务器资源吗?还是有什么文章?也许我没有提到的另一种方法?

在MySQL InnoDB中,选择COUNTid,其中secondary_index=?这是一个昂贵的操作,当用户有很多消息时,此查询可能需要很长时间。即使使用索引,引擎仍然需要统计所有匹配的记录。随着消息总数的增加,性能将下降

另一方面,选择MAXid,其中secondary_index=?通过在索引的B树结构中进行简单的深入分析,可以在几乎恒定的时间内交付该索引中的最高id

如果您想理解为什么,请考虑一下数据结构是如何工作的,这是由UnIDB用来构造表和索引行的。 我建议您使用selectmaxid,如果要求只检查是否有新消息,而不是检查它们的数量


此外,如果您依赖消息计数,则可能会在比赛条件下产生差距。如果用户在两个轮询间隔之间删除一条消息并收到一条新消息,该怎么办?

要获得某人有新消息的信息,请准确地执行此操作。更新users表中的字段,我假设这是系统中记录新消息时的名称。你有收件人的身份证,这就是你所需要的。您可以创建一个插入后触发器假设:有一个users2messages表,它使用一个布尔标志更新users表,该标志指示存在一条消息

这种方法比计算索引(无论是主索引还是次索引)快得多。当用户执行操作时,您可以使用has_messages=0更新用户表,当新消息到达时,您可以使用has_messages=1更新表。它很简单,可以工作,可以扩展,使用触发器来维护它使它变得简单和无缝。
我肯定会有不喜欢触发器的反对者,您可以在将用户与新消息关联时手动执行此操作。

如果您需要知道新消息的数量,请使用 从发件人、收件人和id中的用户id>最后一次看到的id将是您的最佳选择的邮件中选择count*

我非常喜欢在可能的情况下使用exists,所以为了确定是否有新邮件,我的查询是Select exists Select 1 from messages where user\u id in sender,recipient and id>last\u seen\u id。exists的好处是,只要找到一条记录,它就会返回true


编辑:为了避免阅读此答案时出现任何混乱,这两个查询还将包括检查发件人、收件人中的其他用户id,以便仅返回两个特定用户之间的消息。

@FeHora您谈到不使用键来节省数据库空间。表设计浪费了更多的数据库空间

ID - Auto Increment, Primary Key (Bigint)
bigint真的有必要吗?让我们假设,每秒钟发送一条消息。a int unsigned足够使用126年。如果你真的有这么多的消息,一个关键是强制性的

Sender - Varchar (32) // Foreign Key to UserID hash from Users DB Table
Recipient - Varchar (32) // Foreign Key to UserID hash from Users DB Table
为什么不使用UserID呢?通常是一个int unsigned

然后我会添加一个可见的标志。顺便说一句,您可以为所有字段添加属性NOTNULL


最后,我推荐@Mjh的变体:Define一个标志在用户记录中有_消息或新的_消息,或两者都有。通常,用户记录是加载的,因此它不是额外的数据库查询。

我认为最好添加一个时间戳列,并对照该值检查是否有较新的记录。查询时间戳或ID,在该列上使用MAX,并确保使用用户ID、时间戳对其进行索引。计算?不知道。但是你可以测量它。每一个查询都会触发数千个查询,并观察机器指标cpu%、mem%、平均负载等。虽然下面这个问题有一个很好的答案,但我怀疑您可能正在优化一些不重要的东西。除非您预期会收到数以百万计的消息,否则我不会担心磁盘空间,特别是因为与其他字段相比,时间戳很小。如果添加时间戳,每一百万条消息的表将大大约5MB。这真的没什么。当表变得非常大时,由于散列的随机性导致的I/O,这些散列将破坏性能。SELECT MAXid将始终使用主索引-是的,除非在未索引字段上有where。@Se
rgioTulentsev我忘了在我的主要帖子中提到,发送者和接收者是用户hash ID的外键——users表中的主键。因此,它将始终被索引。@Kaii此外,如果您依赖消息计数,您可能会为比赛条件打开一个缺口。如果用户在两个轮询间隔之间删除一条消息并收到一条新消息,该怎么办?如果用户删除了出于安全原因而隐藏的消息,则该消息将有一个隐藏值:true。但是如果a上有索引,则计数不会改变,然后从tbl中选择MAXid,其中a=常量使用所谓的松散索引扫描。这些速度几乎是奇迹般的快。从tbl中选择COUNT*,其中a=常量会进行严格的索引扫描,但速度没有这么快。@FeHora我强烈建议您设置某种测试环境,一个包含生成记录的数据库供您使用。@Kaii SELECT有来自id=1的用户的消息;是最快的查询。这是一个eq_ref,它比计算表中的记录数要快得多。布尔字段不在WHERE子句中,主键为。拜托,下次再好好想想。关于更新表:更新也很快,它处理使用主键定位的单个行。如果该字段已包含要更新的值,则不会发生实际的磁盘I/O,并且性能损失最小。比清点记录要少得多。你可以测量。MAX不是计数,工作方式完全不同。但是,嘿,继续忽略这个事实,继续。暂时锁定,直到评论平静下来。提出你的观点,就这样吧。评论不是为了进行长时间的辩论,也不是为了侮辱。@Kali-你是如何利用旧id来检查新的MAXid的?顺便说一句,早在添加松散索引扫描之前,MAXid就在MySQL中进行了优化。我怀疑松散索引扫描与此讨论无关。是的,查找MAXid是一个简单的BTree向下钻取;它只是在“结束”而不是“开始”。这个消息传递系统是为一个政府ish组织提供的,90%的消息都是从诸如室温高于30摄氏度等系统发送给用户的。。它每小时可以生成数百万条消息,这就是为什么我需要优化每微秒的服务器时间。我不能使用用户ID密钥,因为逆向工程+GDPR EU。长话短说-我需要所有的加密和快速。每一个额外的数据字段都会导致大量多余的数据库存储空间。@FeHora如果您所写的是真的,那么接受的答案正是您想要避免的。百万条记录每小时仅每秒插入278次。即使是旧的机械驱动程序也能驱动约400 IOPS的速度,当前SSD的启动速度为5k IOPS,而获得250k IOPS的驱动器不再昂贵。如果它是政府资产,我想你不会在Raspberry Pi上运行它,而是在一台具有足够RAM和128GB RAM存储、几TB SSD的服务器上运行它。这只是意味着你的微优化不值得。但是,建议外键使用varchar32键是。。很糟糕,为什么@Mjh?在最终用户android应用程序cookie中,如果有新邮件,则只会写入一次,因此不会影响数据库系统/性能。在用户打开“新消息”选项卡之前,只能选择一个选项。该应用程序具有移动通知,仅在本地intranet应用程序中有效。因此,公认的答案是,服务器资源成本最低。现在我有800多名用户登录,DB服务器/web服务器负载约为2%。我使用的是故障转移,所以数据也必须实时发送到备份服务器。2%真的不算太多。@FeHora,因为这不是最快的解决方案。您的负载将保持在较低水平,但由于服务器负载较低,因此选择的方法是最佳的结论是错误的。目前,您还不知道自己是I/O还是CPU绑定—您将是I/O绑定—99.9%的DB操作是I/O绑定的操作。在设计数据库的同时避免外键约束非常糟糕,这证明过早优化是万恶之源。您以性能为借口选择了不一致的数据。你从来没有衡量过你的服务器能做什么,以及它在哪里显示出放缓的迹象。很明显,你意识到你在做什么,但你完全错了。一台服务器都不够,您也不能因为认为一致性会导致性能降级而选择忽略特性和忽略一致性。即使是现在,当你的东西运行时,你看到你的负载非常糟糕,这意味着一个3列的复合索引。
seen tinyint not NULL.