Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/42.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
混合MySQL/非规范化数据存储优化REST API性能_Mysql_Rest_Symfony_<img Src="//i.stack.imgur.com/RUiNP.png" Height="16" Width="18" Alt="" Class="sponsor Tag Img">elasticsearch_Doctrine - Fatal编程技术网 elasticsearch,doctrine,Mysql,Rest,Symfony,elasticsearch,Doctrine" /> elasticsearch,doctrine,Mysql,Rest,Symfony,elasticsearch,Doctrine" />

混合MySQL/非规范化数据存储优化REST API性能

混合MySQL/非规范化数据存储优化REST API性能,mysql,rest,symfony,elasticsearch,doctrine,Mysql,Rest,Symfony,elasticsearch,Doctrine,我有一个用PHP(Symfony 3)和MySQL(Doctrine)构建的web应用程序。 这一切都很好,现在我想构建一个RESTAPI,使应用程序数据的某些部分公开 为了简化事情,假设我有一个/products页面,每个产品都有一个details页面/product/{id}。 在“产品”页面上,用户可以对产品列表应用多个过滤器,例如他们想要的类别。 大多数过滤器只是用户可以选择的复选框列表(没有基于文本的过滤器) 产品表有很多关系,即使它没有被过度规范化;这是我工作领域的固有特性。 为了获

我有一个用PHP(Symfony 3)和MySQL(Doctrine)构建的web应用程序。 这一切都很好,现在我想构建一个RESTAPI,使应用程序数据的某些部分公开

为了简化事情,假设我有一个/products页面,每个产品都有一个details页面/product/{id}。 在“产品”页面上,用户可以对产品列表应用多个过滤器,例如他们想要的类别。 大多数过滤器只是用户可以选择的复选框列表(没有基于文本的过滤器)

产品表有很多关系,即使它没有被过度规范化;这是我工作领域的固有特性。 为了获得单个产品行的所有数据,我必须在15个单独的查询中进行+20个连接。 是的,我知道,这是很多,但大多数表只是简单的查找表,总查询时间只需要+-3ms。 产品列表的过滤是使用纯SQL查询生成器完成的。 因为products页面只显示产品名称的列表,所以性能在这里没有问题

但问题是:RESTAPI必须生成包含所有数据(而不仅仅是名称)的完整产品对象列表。 可以想象,过滤+所有额外的连接/查询和分组对性能来说并不是很好。 为了解决这个问题,我一直在考虑构建某种混合系统,只使用SQL向数据库写入更新,并保留一个只读的非规范化文档存储来获取产品

我能想到的最简单的实现是创建一个product_api_缓存表,该表将生成的产品存储为JSON,准备在api中显示。 如果用户请求/api/products资源,查询生成器将应用过滤器返回产品ID列表,然后我可以使用该列表从product\u api\u缓存表中获取产品JSON

更高级的实现是使用适当的文档存储,如ElasticSearch或MongoDB。 不过,我不确定这将如何与当前的过滤系统(SQL查询生成器)配合使用。 这是否意味着我必须复制专门用于ElasticSearch的所有过滤逻辑

此外,API返回的JSON并没有100%映射到实际的产品对象(通过序列化,它得到了相当大的简化)。 这是否意味着我必须编写两个独立的序列化层?第一个用于存储产品对象的1对1 JSON版本,以便ElasticSearch能够正确地查询它,第二个用于将ElasticSearch的结果序列化为用户的简化视图。 因为ElasticSearch返回JSON,这是否意味着我必须将此结果反序列化到product对象,然后再次序列化product对象


实现这一目标的明智方式是什么?还有更多的方法吗?我想得不对吗?

我认为最简单、最快的解决方案是存储API响应对象的缓存版本。当然,您将拥有重复的数据。根据你的情况,你可以决定它是否可以接受。如果数据库大小不超过几GB,我不会担心。(亲属)

如果你使用弹性搜索,你必须像你所想的那样抽象你的过滤逻辑。但是您也可以在ES中使用mysql表策略(id=data),但这样您将使用ES来检索数据


只是提醒一下。你真的需要这种优化吗?你可能不需要它。这肯定不是性能方面的问题。但是,如果您根本不需要,为什么要使代码库复杂化呢

我将重点讨论非规范化表选项。如果您构建一个非规范化的表来读取数据,那么您基本上就是在实现CQR(请参阅)。我这样做过几次,“包装器对象”将原始对象作为其属性之一,例如:

class ProductExtended {

    /** @var Product **/
    private $product;

    /** @var float **/
    private $originalPrice;

    /** @var float **/
    private $discountedPrice;

   ...
您可以像查询任何其他实体一样查询您的
ProductExtended
实体,但在DB中,这是一个单独的表,因此只要添加到
ProductExtended
所有可搜索属性,性能就会更好,过滤也会更简单


努力保持此表的更新:您需要为
产品
的任何更改添加侦听器,可能还需要一个命令来重新生成所有内容,以确保捕获任何“手动”或未侦听的更改。

我将重点关注ElasticSearch选项。如果使用ES,则不需要按“原样”索引实体。您可以构建一个非规范化版本和索引,而不是版本,这样您就可以利用ES的所有高级过滤选项(不,您不能使用传统的
QueryBuilder
和DQL)。实体ID将是DB实体和ES数据之间的链接


如果您有一些高级过滤逻辑和/或许多数据,这是一条您可能想要探索的道路。ES功能非常强大,速度非常快(如果与Doctrine正确集成),它将返回原始实体作为结果,因此从API使用者的角度来看,它是透明的。

MySQL本身具有本机支持。事实上,它实际上也可以像MongoDB一样工作。

这确实是一个比只存储JSON更好的解决方案,因为这个包装器对象也可以在API之外使用以加快速度;也许我可以用更好的措辞。问题是规范化,但数据本身不能真正去规范化,因为它本质上是分层的。我提出的第一个解决方案将作为缓存使用,但我认为使用CQR不可能实现这一点?基本上,我需要的是产品对象的一个近乎精确的副本,但没有连接的所有开销。我现在可能确实不需要ElasticSearch,但将来可能需要更高级的文本搜索。虽然它可能更复杂,但它可能是一次很好的学习经历。