我在Pyramid python Web框架中有关于URL遍历的问题。
想象一下论坛的以下端点:
/forum/1 - Returns information about Forum #1
/forum/1/threads/1 - Returns Thread #1 in Forum #1
以下是遍历对第一个URL的作用:
Root
资源Root.__getitem__("forum")
被调用。这将返回ForumDispatch
资源。ForumDispatch.__getitem__("1")
被调用。将为ID为1的论坛查询数据库。如果找不到,则引发KeyError
。如果找到,则返回Forum
对象,视图查找以Forum
作为上下文开始。以下是遍历对第二个URL的作用
Root
资源Root.__getitem__("forum")
被调用。这将返回ForumDispatch
资源。ForumDispatch.__getitem__("1")
被调用。将查询数据库中标识为1的Forum
。如果找不到,则引发KeyError
。如果找到,则返回Forum
个对象。Forum.__getitem__("threads")
被调用。返回ThreadsDispatch
个对象ThreadsDispatch.__getitem__("1")
被调用。在Thread
#1中查询数据库中的Forum
#1。如果找到,则返回Thread
对象并开始查看视图,或者引发KeyError
。现在,对于第一个URL,将发出单个查询。它看起来像SELECT ... FROM forums WHERE forums.id = 1;
。在第二个URL中,发出两个查询。 SELECT ... FROM forums WHERE forums.id = 1;
和SELECT ... FROM threads WHERE thread.id = 1 AND forum.id = 1;
。
我不希望发出两个查询。对于第二个URL,查询SELECT ... FROM forums LEFT JOIN threads ON threads.forum_id = forums.id WHERE threads.id = 1 AND forums.id = 1;
将返回所需的所有信息。然后,如果没有返回任何行,或者返回Forum
但不返回Thread
,我可以返回KeyError。
为了实现这一点,ForumDispatch.__getitem__
需要表现得不同(例如,更改查询,或根本不查询),如果它知道“线程”也将在下一次调用。
有没有办法实现这个目标?
我可以,而不是返回实际的数据库对象,创建由ForumDispatch.__getitem__
等返回的“虚拟”资源,然后让视图执行必要的查询。但是,我觉得我失去了一些遍历功能,让视图担心查询/引发404错误。想法?
答案 0 :(得分:0)
您的问题是过早优化的书本案例:)
通过主键从数据库中获取单行是数据库可以执行的最快操作。我希望它需要大约1毫秒或更短的时间。
带有连接的查询稍微复杂一些,涉及访问两个表和一个索引并执行实际连接。最重要的是它会花费更长的时间 - 比如说,它比单行提取慢约50%,大约1.5毫秒。根据行数,它实际上可能需要更多,因为连接不是完全免费的。
因此,进行两个简单查询的总时间约为2毫秒,而连接查询约为1.5毫秒。因此,您最多只能看到~0.5 ms的差异。或者没有。或许有点慢,你永远不会知道。无论如何,如果你把它放在网络应用程序的上下文中,与网络延迟,HTTP往返,浏览器页面重排等相比,任何节省都是完全可以忽略不计的。你可以获得更多优惠,以便花费你的时间来优化你可以获得一些可衡量的好处的领域:)
当然,当您发现您的网页正在进行数十次或数百次查询时(通常是在显示列表时),是时候花时间在SQLAlchemy中配置eager-loading。用一个更复杂的查询替换两个简单查询只会使事情变得复杂而不会带来任何可衡量的好处。