【问题标题】:speeding up mysql queries / mysql views in django加快 django 中的 mysql 查询/mysql 视图
【发布时间】:2011-04-09 04:49:18
【问题描述】:

我使用以下代码从数据库中选择热门新闻条目(按日期):

popular = Entry.objects.filter(type='A', is_public=True).extra(select = {'dpub': 'date(dt_published)'}).order_by('-dpub', '-views', '-dt_written', 'headline')[0:5]

为了比较普通查询和这个查询的执行速度,我运行了以下 mysql 查询:

SELECT *, date(dt_published) as dpub FROM `news_entry` order by dpub DESC LIMIT 500

# Showing rows 0 - 29 (500 total, Query took 0.1386 sec)

-

SELECT * , DATE( dt_published ) AS dpub FROM  `news_entry` ORDER BY id DESC LIMIT 500

# Showing rows 0 - 29 (500 total, Query took 0.0021 sec) [id: 58079 - 57580]

如您所见,普通查询要快得多。有没有办法加快速度?

django 可以使用 mysql 视图吗?

我意识到我可以将日期时间字段分成两个字段(日期和时间),但我很好奇。


结构:

CREATE TABLE IF NOT EXISTS `news_entry` (
  `id` int(11) NOT NULL DEFAULT '0',
  `views` int(11) NOT NULL,
  `user_views` int(11) NOT NULL,
  `old_id` int(11) DEFAULT NULL,
  `type` varchar(1) NOT NULL,
  `headline` varchar(256) NOT NULL,
  `subheadline` varchar(256) NOT NULL,
  `slug` varchar(50) NOT NULL,
  `category_id` int(11) DEFAULT NULL,
  `is_public` tinyint(1) NOT NULL,
  `is_featured` tinyint(1) NOT NULL,
  `dt_written` datetime DEFAULT NULL,
  `dt_modified` datetime DEFAULT NULL,
  `dt_published` datetime DEFAULT NULL,
  `author_id` int(11) DEFAULT NULL,
  `author_alt` varchar(256) NOT NULL,
  `email_alt` varchar(256) NOT NULL,
  `tags` varchar(255) NOT NULL,
  `content` longtext NOT NULL
) ENGINE=MyISAM DEFAULT;

【问题讨论】:

    标签: mysql django django-models query-optimization sql-view


    【解决方案1】:
    SELECT *, date(dt_published) as dpub FROM `news_entry` order by dpub DESC LIMIT 500
    

    这个查询在dpub上订购,而这个:

    SELECT * , DATE( dt_published ) AS dpub FROM  `news_entry` ORDER BY id DESC LIMIT 500
    

    id上的订单。

    因为id 很可能是您的表的PRIMARY KEY,并且每个PRIMARY KEY 都有一个隐式索引支持它,所以ORDER BY 不需要排序。

    dpub 是计算域,MySQL 不支持计算域上的索引。但是,ORDER BY dt_published 也是 ORDER BY dpub

    您需要将查询更改为:

    SELECT *, date(dt_published) as dpub FROM `news_entry` order by date_published DESC LIMIT 500
    

    并在news_entry (dt_published) 上创建索引。

    更新:

    由于DATE 是一个单调函数,你可以使用这个技巧:

    SELECT  *, DATE(dt_published) AS dpub
    FROM    news_entry
    WHERE   dt_published >=
            (
            SELECT  md
            FROM    (
                    SELECT  DATE(dt_published) AS md
                    FROM    news_entry
                    ORDER BY
                            dt_published DESC
                    LIMIT 499, 1
                    ) q
            UNION ALL
            SELECT  DATE(MIN(dt_published))
            FROM    news_entry
            LIMIT 1
            )
    ORDER BY
            dpub DESC, views DESC, dt_written DESC, headline
    LIMIT 500
    

    此查询执行以下操作:

    • dt_published DESC 的顺序选择500th 记录,或者如果表中的记录少于500,则选择第一个发布的记录。

    • 获取晚于所选最后一条记录的日期发布的所有记录。由于DATE(x) 总是小于或等于x,所以可以有超过500 的记录,但仍然 比整张桌子少得多。

    • 酌情对这些记录进行排序和限制。

    您可能会觉得这篇文章很有趣,因为它涵盖了类似的问题:

    【讨论】:

    • 感谢您提供数据化的答案。然而,这不是我的问题的答案。我知道我无法在计算字段上创建索引。但是我对视图不是很熟悉,所以我认为如果我对它们了解更多,它们可能会对我有所帮助。无法通过 dt_published 订购,因为我还想通过查看/点击订购。 order_by('-dpub', '-views', '-dt_written', 'headline')
    • @Arnar: MySQL 无法将谓词推送到视图中:视图将首先执行和缓冲,然后应用所有其他谓词。如果你需要通过额外的字段排序,你可以实现一个技巧(我现在将它放在帖子中)。
    【解决方案2】:

    可能需要dt_published 上的索引。您能否发布两个查询的查询计划?

    【讨论】:

    • 我试过了,但问题是 dpub 是一个计算字段,它不能是一个索引。
    • 不,不在 dpub 上...在 news_entry (dt_published) 上创建索引 inx_news_entry_dt;它可能会有所帮助。
    • 为问题添加了表格结构,是的,我做到了。
    猜你喜欢
    • 2016-10-05
    • 2013-03-29
    • 1970-01-01
    • 1970-01-01
    • 2011-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多