如何在类别中搜索时优化连接

时间:2016-12-10 15:30:22

标签: mysql categories

我有一个包含物品的表格:

from django.utils import translation

class MyAdapter(DefaultAccountAdapter):

    def render_mail(self, template_prefix, email, context):
        # Set language, based on `email`, or `self.request.session`, or
        # whatever fits your project
        #
        # TODO: insert your logic here
        lang = 'nl'  

        with translation.override(lang):
             return super().render_mail(template_prefix, email, context)

表格,用于连接具有类别的项目:

CREATE TABLE `ost_content` (
  `uid` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
  `type` enum('media','serial','season','series') NOT NULL,
  `alias` varchar(200) NOT NULL,
  `views` mediumint(7) NOT NULL DEFAULT '0',
  `ratings_count` enum('0','1','2','4','5') NOT NULL DEFAULT '0',
  `ratings_sum` mediumint(5) NOT NULL DEFAULT '0',
  `upload_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `conversion_status` enum('converting','error','success','announcement') NOT NULL DEFAULT 'converting',
  PRIMARY KEY (`uid`),
  UNIQUE KEY `idx_uid_type` (`uid`,`type`),
  KEY `idx_type` (`type`),
  KEY `idx_upload_date DESC` (`upload_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

比,我执行查询:

CREATE TABLE `ost_categories2media` (
  `categories2media_id` mediumint(6) unsigned NOT NULL AUTO_INCREMENT,
  `categories2media_category_id` smallint(5) unsigned NOT NULL,
  `categories2media_uid` mediumint(8) unsigned NOT NULL,
  PRIMARY KEY (`categories2media_id`),
  KEY `categories2media_media_id` (`categories2media_uid`),
  KEY `categories2media_category_id` (`categories2media_category_id`)
) ENGINE=InnoDB AUTO_INCREMENT=501114 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

执行缓慢,categories2media_category_id检查多行:

SELECT
    c1.uid,
    c1.alias,
    c1.type,
    c1.views,
    c1.upload_date,
    c1.ratings_sum,
    c1.ratings_count,
    c1.conversion_status
FROM
    ost_content c1
LEFT JOIN ost_categories2media c2m ON c2m.categories2media_uid = c1.uid
WHERE
    c2m.categories2media_category_id = '53'
AND c1.conversion_status IN ('success', 'announcement')
AND c1.type IN ('serial', 'media')
ORDER BY
    c1.upload_date DESC
LIMIT 16, 16

如何优化或重写此查询?

2 个答案:

答案 0 :(得分:0)

Mysql索引就像cooks,其中太多都不是很有用,因为mysql每个表只使用一个索引。我们来看看ost_categories2media, 这是三列上的三个独立索引。你最好使用这样的两个索引。

  PRIMARY KEY (`categories2media_id`),
  KEY `categories2media_media_id` (`categories2media_uid`,`categories2media_category_id`)

现在,mysql不再需要在categories2media_uidcategories2media_category_id之间做出索引,它有一个涵盖两者的索引!

查看您的ost_content表,我们看到了

  PRIMARY KEY (`uid`),
  UNIQUE KEY `idx_uid_type` (`uid`,`type`),
  KEY `idx_type` (`type`),
  KEY `idx_upload_date DESC` (`upload_date`)

其中一些索引有点多余。在uid字段上过滤的任何查询都可以使用PK,而在type上过滤的任何查询都可以使用idx_type,这意味着idx_uid_type只是为了强制执行唯一性。但我们可以让它更有用:

  PRIMARY KEY (`uid`),
  UNIQUE KEY `idx_uid_type` (`type`,`uid`),
  KEY `idx_upload_date DESC` (`upload_date`)

我们已经摆脱了一个指数!应该让你的索引更快。您仍然在upload_date上有一个索引,该索引未在此特定查询中使用。那么综合指数怎么样?

  PRIMARY KEY (`uid`),
  UNIQUE KEY `idx_uid_type` (`type`,`uid`),
  KEY `idx_upload_date DESC` (`uid`,`upload_date`)

答案 1 :(得分:0)

首先,from flask import Flask from flask_sqlalchemy import SQLAlchemy app=Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:myPassword@myServer/firstdb' app.config['SQLALCHEMY_ECHO'] = False app.config['SQLALCHEMY_TRACK_MODIFICATIONS']=True app.config['MYSQL_DATABASE_CHARSET'] = 'utf8mb4' db = SQLAlchemy(app) class Users(db.Model): __tablename__='users' id=db.Column('iduser', db.Integer, primary_key=True) name=db.Column('column_name', db.String(193)) def __init__(self, name): self.name=name def __repr__(self): return self.name.decode('utf-8') db.create_all() db.session.commit() president1=Users('Obama') president2=Users('Trump') db.session.add(president1) db.session.add(president2) db.session.commit() 不是必需的。因此,您可以将查询编写为:

(competeEnv) C:\Users\MyName\Anaconda3.1\envs>python
Python 2.7.12 |Continuum Analytics, Inc.| (default, Jun 29 2016, 11:07:13)[MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
Anaconda is brought to you by Continuum Analytics.

>>> from testAlchemy import Users, db
>>> db.session.add(Users('Federer'))
>>> db.session.commit()
>>> Users.query.all()
[Obama, Trump, Federer]
>>> db.session.add(Users(u'ä'))
>>> db.session.commit()
>>> Users.query.all()
[Obama, Trump, Federer, Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "testAlchemy.py", line 23, in __repr__
    return self.name.decode('utf-8')
  File "C:\Users\MyName\Anaconda3.1\envs\envNew\lib\encodings\utf_8.py", line 16, in decode
    return codecs.utf_8_decode(input, errors, True)
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe4' in position 0: ordinal not in range(128)
>>>

不幸的是,您在内容表上的条件不是简单的LEFT JOIN条件。如果是,则建议使用SELECT c.* FROM ost_content c JOIN ost_categories2media c2m ON c2m.categories2media_uid = c.uid WHERE c2m.categories2media_category_id = '53' AND c.conversion_status IN ('success', 'announcement') AND c.type IN ('serial', 'media') ORDER BY c.upload_date DESC LIMIT 16, 16; 上的索引。这可能仍然是更好的选择。

另一种选择是采用另一种方式:=上的索引。

您可能会发现第一个复合索引和此查询效果最佳:

ost_content(conversion_status, type, uid)

这看起来更复杂,但每个子查询都可以利用索引,因此可能会提高性能。