2010-11-10 27 views
7

一个(简化的)Internet书签数据库。我觉得这一定是有意义的逻辑组织表,就像这样:在SQLite中连接三个表的最佳方式

Bookmarks (id, title, url; basically external data) 
+------+------------+-----+ 
| suid | Title | ... | 
+------+------------+-----+ 

User (user-specific data: favorites, ratings, etc) 
+------+------------+-----+ 
| suid | IsFavorite | ... | 
+  + (0 or 1) +  + 
+------+------------+-----+ 

History (last used, use count etc) 
+------+------------+-----+ 
| suid | LastUsed | ... | 
+  +(TDateTime) +  + 
+------+------------+-----+ 

(“SUID”是唯一的ID,整数主键)

从标记为喜欢书签,我需要选择N 最近使用过(为了便利,在运行时在菜单中填充菜单)。

SELECT Bookmarks.suid, Title from Bookmarks 
    INNER JOIN User USING (suid) 
    INNER JOIN History USING (suid) 
    WHERE IsFavorite = 1 
    ORDER BY LastUsed DESC 
    LIMIT 15; 

该声明起作用,并且似乎具有足够的可读性,但它是否最优?书签表的目的是平均保存20-50k条记录(即,不是您的标准浏览器书签管理器:-)应用程序将在启动时执行3或4条类似语句来填充控件。示例中使用的所有字段都被编入索引。

我在教自己的SQL,并提出了上面的代码,但也许我忽略了一种语法或可以改善它的成语吗?

+0

如果收藏指标存储在用户表中,那么推断出与用户关联的所有书签都是收藏夹 - 它需要位于书签级别,或者我误解了目的。 – 2010-11-10 17:23:45

+0

我有一个倾向于在我的问题中过度解释,所以我编造了一个简单的例子来避免这个问题。主书签表将定期更新。在更新期间,我不想触摸用户输入的任何数据,例如评分,标记为收藏夹等。将两者分开似乎更为清晰。同样,一些用户可能不想保留历史记录,在这种情况下,应用程序可以清除或删除整个历史记录表。 (或者,'用户'这个名字可能是误导性的,它不是用户帐户数据的表格,而是用户输入的数据点,它是一个单用户桌面应用程序。) – 2010-11-10 22:29:06

回答

4

从原始SQL猜测数据库引擎如何满足查询是不可能的(或者至少非常非常困难)。出于这个原因,您需要使用EXPLAIN来了解SQLite如何实际获取数据。并且请注意,它产生的执行计划将会有所不同,具体取决于每个表中的数据量以及数据“看起来”的类似程度(根据索引列中的不同值的数量)。因此,请确保使用真实的数据填充测试数据库。

一旦您尝试EXPLAIN,我认为有可能您会发现SQLite在进行前15个匹配之前一起将这些表连接在一起,如果属实,这将是非最优的。如果原来是这样,你可以尝试这样的:

SELECT Bookmarks.suid, Title from Bookmarks 
    INNER JOIN User USING (suid) 
    WHERE IsFavorite = 1 
    AND suid IN (SELECT suid FROM History ORDER BY LastUsed DESC LIMIT 15); 

但是,再次强调,不要尝试,直到你看到从该EXPLAIN SQLite是在非最佳的方式获取数据。

0

它看起来对我好。您可能已经知道这一点,但如果您想进一步调整,可以使用explain关键字(http://www.sqlite.org/lang_explain.html)调查您的查询。

干杯!

0

您可以像前面所说的那样使用关键字EXPLAIN,但还有其他方法可以改进它。 有一个网站的一些信息...检查出点击'here了解更多关于它... 祝你好运!

相关问题