mysql编译优化,mysql如何进行优化

发布时间:2022-11-19

本文目录一览:

  1. mysql数据库如何优化?谁能给出点具体的解决方案?
  2. MySQL语句优化技巧?
  3. MySQL数据库性能优化有哪些技巧?
  4. mysql优化的几种方法
  5. mysql如何优化以下语句,查询耗时太久了?

mysql数据库如何优化?谁能给出点具体的解决方案?

  • EXPLAIN:解释SQL的执行计划,后面的SQL不执行。
  • EXPLAIN PARTITIONS:用于查看存在分区的表的执行计划。
  • EXPLAIN EXTENDED:待验证。
  • SHOW WARNINGS
  • SHOW CREATE TABLE:查看表的详细的创建语句,便于用户对表进行优化。
  • SHOW INDEXES:查看表的所有索引,SHOW INDEXES FROM table_name,同样也可以从INFORMATION_SCHEMA.STATISTICS表中获得同样的信息。CARDINALITY列很重要,表示数据量。
  • SHOW TABLES STATUS:查看数据库表的底层大小以及表结构,同样可以从INFORMATION_SCHEMA.TABLES表中获得底层表的信息。
  • SHOW [GLOBAL|SESSION] STATUS:可以查看MySQL服务器当前内部状态信息。可以帮助确认MySQL服务器的负载的各种指标。默认是SESSION。同INFORMATION_SCHEMA.GLOBAL_STATUSINFORMATION_SCHEMA.SESSION_STATUS
  • SHOW [GLOBAL|SESSION] VARIABLES:查看当前MySQL系统变量的值,其中一些值能影响到SQL语句的执行方式。同INFORMATION_SCHEMA.GLOBAL_VARIABLESINFORMATION_SCHEMA.SESSION_VARIABLES
  • INFORMATION_SCHEMA:包含的表的数量和MySQL的版本有关系。

MySQL语句优化技巧?

  1. 应尽量避免在 WHERE 子句中使用 != 或操作符,否则将引擎放弃使用索引而进行全表扫描。
  2. 对查询进行优化,应尽量避免全表扫描,首先应考虑在 WHEREORDER BY 涉及的列上建立索引。
  3. 应尽量避免在 WHERE 子句中对字段进行 NULL 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:
    SELECT ID FROM T WHERE NUM IS NULL
    
    可以在 NUM 上设置默认值 0,确保表中 NUM 列没有 NULL 值,然后这样查询:
    SELECT ID FROM T WHERE NUM = 0
    
  4. 尽量避免在 WHERE 子句中使用 OR 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:
    SELECT ID FROM T WHERE NUM = 10 OR NUM = 20
    
    可以这样查询:
    SELECT ID FROM T WHERE NUM = 10
    UNION ALL
    SELECT ID FROM T WHERE NUM = 20
    
  5. 下面的查询也将导致全表扫描:(不能前置百分号)
    SELECT ID FROM T WHERE NAME LIKE '%C%'
    
    若要提高效率,可以考虑全文检索。
  6. INNOT IN 也要慎用,否则会导致全表扫描,如:
    SELECT ID FROM T WHERE NUM IN (1, 2, 3)
    
    对于连续的数值,能用 BETWEEN 就不要用 IN 了:
    SELECT ID FROM T WHERE NUM BETWEEN 1 AND 3
    
  7. 如果在 WHERE 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描:
    SELECT ID FROM T WHERE NUM = @NUM
    
    可以改为强制查询使用索引:
    SELECT ID FROM T WITH(INDEX(索引名)) WHERE NUM = @NUM
    
  8. 应尽量避免在 WHERE 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:
    SELECT ID FROM T WHERE NUM / 2 = 100
    
    应改为:
    SELECT ID FROM T WHERE NUM = 100 * 2
    
  9. 应尽量避免在 WHERE 子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:
    SELECT ID FROM T WHERE SUBSTRING(NAME, 1, 3) = 'ABC' -- NAME 以 ABC 开头的 ID
    SELECT ID FROM T WHERE DATEDIFF(DAY, CREATEDATE, '2005-11-30') = 0 -- '2005-11-30' 生成的 ID
    
    应改为:
    SELECT ID FROM T WHERE NAME LIKE 'ABC%'
    SELECT ID FROM T WHERE CREATEDATE = '2005-11-30' AND CREATEDATE < '2005-12-1'
    
  10. 不要在 WHERE 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。
  11. 在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。
  12. 不要写一些没有意义的查询,如需要生成一个空表结构:
    SELECT COL1, COL2 INTO #T FROM T WHERE 1=0
    
    这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样:
    CREATE TABLE #T(...)
    
  13. 很多时候用 EXISTS 代替 IN 是一个好的选择:
    SELECT NUM FROM A WHERE NUM IN (SELECT NUM FROM B)
    
    用下面的语句替换:
    SELECT NUM FROM A WHERE EXISTS (SELECT 1 FROM B WHERE NUM = A.NUM)
    
  14. 并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段 SEXMALEFEMALE 几乎各一半,那么即使在 SEX 上建了索引也对查询效率起不了作用。
  15. 索引并不是越多越好,索引固然可以提高相应的 SELECT 的效率,但同时也降低了 INSERTUPDATE 的效率,因为 INSERTUPDATE 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有
  16. 应尽可能的避免更新 CLUSTERED 索引数据列,因为 CLUSTERED 索引数据列的顺序就是表记录的物理存储顺序,一旦该列值改变将导致整个表记录的顺序的调整,会耗费相当大的资源。若应用系统需要频繁更新 CLUSTERED 索引数据列,那么需要考虑是否应将该索引建为 CLUSTERED 索引。
  17. 尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。
  18. 尽可能的使用 VARCHAR/NVARCHAR 代替 CHAR/NCHAR,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。
  19. 任何地方都不要使用 SELECT * FROM T,用具体的字段列表代替“*”,不要返回用不到的任何字段。
  20. 尽量使用表变量来代替临时表。如果表变量包含大量数据,请注意索引非常有限(只有主键索引)。
  21. 避免频繁创建和删除临时表,以减少系统表资源的消耗。
  22. 临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用表中的某个数据集时。但是,对于一次性事件,最好使用导出表。
  23. 在新建临时表时,如果一次性插入数据量很大,那么可以使用 SELECT INTO 代替 CREATE TABLE,避免造成大量 LOG,以提高速度;如果数据量不大,为了缓和系统表的资源,应先 CREATE TABLE,然后 INSERT
  24. 如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 TRUNCATE TABLE,然后 DROP TABLE,这样可以避免系统表的较长时间锁定。
  25. 尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。
  26. 使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方案来解决问题,基于集的方法通常更有效。
  27. 与临时表一样,游标并不是不可使用。对小型数据集使用 FAST_FORWARD 游标通常要优于其他逐行处理方法,尤其是在必须引用几个表才能获得所需的数据时。在结果集中包括“合计”的例程通常要比使用游标执行的速度快。如果开发时间允许,基于游标的方法和基于集的方法都可以尝试一下,看哪一种方法的效果更好。
  28. 在所有的存储过程和触发器的开始处设置 SET NOCOUNT ON,在结束时设置 SET NOCOUNT OFF。无需在执行存储过程和触发器的每个语句后向客户端发送 DONE_IN_PROC 消息。
  29. 尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。
  30. 尽量避免大事务操作,提高系统并发能力。

MySQL数据库性能优化有哪些技巧?

  1. 存储引擎的选择
    如果数据表需要事务处理,应该考虑使用 InnoDB,因为它完全符合 ACID 特性。如果不需要事务处理,使用默认存储引擎 MyISAM 是比较明智的。并且不要尝试同时使用这两个存储引擎。思考一下:在一个事务处理中,一些数据表使用 InnoDB,而其余的使用 MyISAM。结果呢?整个事务将被取消,只有那些在事务处理中的被带回到原始状态,其余的被提交的数据转存,这将导致整个数据库的冲突。然而存在一个简单的方法可以同时利用两个存储引擎的优势。目前大多数 MySQL 套件中包括 InnoDB、编译器和链表,但如果你选择 MyISAM,你仍然可以单独下载 InnoDB,并把它作为一个插件。很简单的方法,不是吗?
  2. 计数问题
    如果数据表采用的存储引擎支持事务处理(如 InnoDB),你就不应使用 COUNT(*) 计算数据表中的行数。这是因为在产品类数据库使用 COUNT(*),最多返回一个近似值,因为在某个特定时间,总有一些事务处理正在运行。如果使用 COUNT(*) 显然会产生 bug,出现这种错误结果。
  3. 反复测试查询
    查询最棘手的问题并不是无论怎样小心总会出现错误,并导致 bug 出现。恰恰相反,问题是在大多数情况下 bug 出现时,应用程序或数据库已经上线。的确不存在针对该问题切实可行的解决方法,除非将测试样本在应用程序或数据库上运行。任何数据库查询只有经过上千个记录的大量样本测试,才能被认可。
  4. 避免全表扫描
    通常情况下,如果 MySQL(或者其他关系数据库模型)需要在数据表中搜索或扫描任意特定记录时,就会用到全表扫描。此外,通常最简单的方法是使用索引表,以解决全表扫描引起的低效能问题。然而,正如我们在随后的问题中看到的,这存在错误部分。
  5. 使用“EXPLAIN”进行查询
    当需要调试时,EXPLAIN 是一个很好的命令,下面将对 EXPLAIN 进行深入探讨。

mysql优化的几种方法

  1. 选取最适用的字段属性
    MySQL 可以很好的支持大数据量的存取,但是一般说来,数据库中的表越小,在它上面执行的查询也就会越快。因此,在创建表的时候,为了获得更好的性能,我们可以将表中字段的宽度设得尽可能小。例如,在定义邮政编码这个字段时,如果将其设置为 CHAR(255),显然给数据库增加了不必要的空间,甚至使用 VARCHAR 这种类型也是多余的,因为 CHAR(6) 就可以很好的完成任务了。同样的,如果可以的话,我们应该使用 MEDIUMINT 而不是 BIGINT 来定义整型字段。
    另外一个提高效率的方法是在可能的情况下,应该尽量把字段设置为 NOT NULL,这样在将来执行查询的时候,数据库不用去比较 NULL 值。
    对于某些文本字段,例如“省份”或者“性别”,我们可以将它们定义为 ENUM 类型。因为在 MySQL 中,ENUM 类型被当作数值型数据来处理,而数值型数据被处理起来的速度要比文本类型快得多。这样,我们又可以提高数据库的性能。
  2. 使用连接(JOIN)来代替子查询(Sub-Queries)
    MySQL 从 4.1 开始支持 SQL 的子查询。这个技术可以使用 SELECT 语句来创建一个单列的查询结果,然后把这个结果作为过滤条件用在另一个查询中。例如,我们要将客户基本信息表中没有任何订单的客户删除掉,就可以利用子查询先从销售信息表中将所有发出订单的客户 ID 取出来,然后将结果传递给主查询,如下所示:
    DELETE FROM customerinfo
    WHERE CustomerID NOT IN (SELECT CustomerID FROM salesinfo)
    
    使用子查询可以一次性的完成很多逻辑上需要多个步骤才能完成的 SQL 操作,同时也可以避免事务或者表锁死,并且写起来也很容易。但是,有些情况下,子查询可以被更有效率的连接(JOIN)替代。例如,假设我们要将所有没有订单记录的用户取出来,可以用下面这个查询完成:
    SELECT * FROM customerinfo
    WHERE CustomerID NOT IN (SELECT CustomerID FROM salesinfo)
    
    如果使用连接(JOIN)来完成这个查询工作,速度将会快很多。尤其是当 salesinfo 表中对 CustomerID 建有索引的话,性能将会更好,查询如下:
    SELECT * FROM customerinfo
    LEFT JOIN salesinfo ON customerinfo.CustomerID = salesinfo.CustomerID
    WHERE salesinfo.CustomerID IS NULL
    
    连接(JOIN)之所以更有效率一些,是因为 MySQL 不需要在内存中创建临时表来完成这个逻辑上的需要两个步骤的查询工作。
  3. 使用联合(UNION)来代替手动创建的临时表
    MySQL 从 4.0 的版本开始支持 UNION 查询,它可以把需要使用临时表的两条或更多的 SELECT 查询合并的一个查询中。在客户端的查询会话结束的时候,临时表会被自动删除,从而保证数据库整齐、高效。使用 UNION 来创建查询的时候,我们只需要用 UNION 作为关键字把多个 SELECT 语句连接起来就可以了,要注意的是所有 SELECT 语句中的字段数目要想同。下面的例子就演示了一个使用 UNION 的查询。
    SELECT Name, Phone FROM client
    UNION
    SELECT Name, BirthDate FROM author
    UNION
    SELECT Name, Supplier FROM product
    
  4. 事务
    尽管我们可以使用子查询(Sub-Queries)、连接(JOIN)和联合(UNION)来创建各种各样的查询,但不是所有的数据库操作都可以只用一条或少数几条 SQL 语句就可以完成的。更多的时候是需要用到一系列的语句来完成某种工作。但是在这种情况下,当这个语句块中的某一条语句运行出错的时候,整个语句块的操作就会变得不确定起来。设想一下,要把某个数据同时插入两个相关联的表中,可能会出现这样的情况:第一个表中成功更新后,数据库突然出现意外状况,造成第二个表中的操作没有完成,这样,就会造成数据的不完整,甚至会破坏数据库中的数据。要避免这种情况,就应该使用事务,它的作用是:要么语句块中每条语句都操作成功,要么都失败。换句话说,就是可以保持数据库中数据的一致性和完整性。事务以 BEGIN 关键字开始,COMMIT 关键字结束。在这之间的一条 SQL 操作失败,那么,ROLLBACK 命令就可以把数据库恢复到 BEGIN 开始之前的状态。
    BEGIN;
    INSERT INTO salesinfo SET CustomerID=14;
    UPDATE inventory SET Quantity=11
    WHERE item='book';
    COMMIT;
    
    事务的另一个重要作用是当多个用户同时使用相同的数据源时,它可以利用锁定数据库的方法来为用户提供一种安全的访问方式,这样可以保证用户的操作不被其它的用户所干扰。
  5. 锁定表
    尽管事务是维护数据库完整性的一个非常好的方法,但却因为它的独占性,有时会影响数据库的性能,尤其是在很大的应用系统中。由于在事务执行的过程中,数据库将会被锁定,因此其它的用户请求只能暂时等待直到该事务结束。如果一个数据库系统只有少数几个用户来使用,事务造成的影响不会成为一个太大的问题;但假设有成千上万的用户同时访问一个数据库系统,例如访问一个电子商务网站,就会产生比较严重的响应延迟。
    其实,有些情况下我们可以通过锁定表的方法来获得更好的性能。下面的例子就用锁定表的方法来完成前面一个例子中事务的功能。
    LOCK TABLE inventory WRITE
    SELECT Quantity FROM inventory
    WHERE Item='book';
    ...
    UPDATE inventory SET Quantity=11
    WHERE Item='book';
    UNLOCK TABLES
    
    这里,我们用一个 SELECT 语句取出初始数据,通过一些计算,用 UPDATE 语句将新值更新到表中。包含有 WRITE 关键字的 LOCK TABLE 语句可以保证在 UNLOCK TABLES 命令被执行之前,不会有其它的访问来对 inventory 进行插入、更新或者删除的操作。
  6. 使用外键
    锁定表的方法可以维护数据的完整性,但是它却不能保证数据的关联性。这个时候我们就可以使用外键。例如,外键可以保证每一条销售记录都指向某一个存在的客户。在这里,外键可以把 customerinfo 表中的 CustomerID 映射到 salesinfo 表中 CustomerID,任何一条没有合法 CustomerID 的记录都不会被更新或插入到 salesinfo 中。
    CREATE TABLE customerinfo
    (
    CustomerID INT NOT NULL ,
    PRIMARY KEY ( CustomerID )
    ) TYPE = INNODB;
    CREATE TABLE salesinfo
    (
    SalesID INT NOT NULL,
    CustomerID INT NOT NULL,
    PRIMARY KEY(CustomerID, SalesID),
    FOREIGN KEY (CustomerID) REFERENCES customerinfo
    (CustomerID) ON DELETE CASCADE
    ) TYPE = INNODB;
    
    注意例子中的参数“ON DELETE CASCADE”。该参数保证当 customerinfo 表中的一条客户记录被删除的时候,salesinfo 表中所有与该客户相关的记录也会被自动删除。如果要在 MySQL 中使用外键,一定要记住在创建表的时候将表的类型定义为事务安全表 InnoDB 类型。该类型不是 MySQL 表的默认类型。定义的方法是在 CREATE TABLE 语句中加上 TYPE=INNODB。如例中所示。
  7. 使用索引
    索引是提高数据库性能的常用方法,它可以令数据库服务器以比没有索引快得多的速度检索特定的行,尤其是在查询语句当中包含有 MAX()MIN()ORDER BY 这些命令的时候,性能提高更为明显。那该对哪些字段建立索引呢?一般说来,索引应建立在那些将用于 JOINWHERE 判断和 ORDER BY 排序的字段上。尽量不要对数据库中某个含有大量重复的值的字段建立索引。对于一个 ENUM 类型的字段来说,出现大量重复值是很有可能的情况,例如 customerinfo 中的“province”字段,在这样的字段上建立索引将不会有什么帮助;相反,还有可能降低数据库的性能。我们在创建表的时候可以同时创建合适的索引,也可以使用 ALTER TABLECREATE INDEX 在以后创建索引。此外,MySQL 从版本 3.23.23 开始支持全文索引和搜索。全文索引在 MySQL 中是一个 FULLTEXT 类型索引,但仅能用于 MyISAM 类型的表。对于一个大的数据库,将数据装载到一个没有 FULLTEXT 索引的表中,然后再使用 ALTER TABLECREATE INDEX 创建索引,将是非常快的。但如果将数据装载到一个已经有 FULLTEXT 索引的表中,执行过程将会非常慢。
  8. 优化的查询语句
    绝大多数情况下,使用索引可以提高查询的速度,但如果 SQL 语句使用不恰当的话,索引将无法发挥它应有的作用。下面是应该注意的几个方面。首先,最好是在相同类型的字段间进行比较的操作。在 MySQL 3.23 版之前,这甚至是一个必须的条件。例如不能将一个建有索引的 INT 字段和 BIGINT 字段进行比较;但是作为特殊的情况,在 CHAR 类型的字段和 VARCHAR 类型字段的字段大小相同的时候,可以将它们进行比较。其次,在建有索引的字段上尽量不要使用函数进行操作。
    例如,在一个 DATE 类型的字段上使用 YEAR() 函数时,将会使索引不能发挥应有的作用。所以,下面的两个查询虽然返回的结果一样,但后者要比前者快得多。
    SELECT * FROM order WHERE YEAR(OrderDate) < 2001;
    SELECT * FROM order WHERE OrderDate < "2001-01-01";
    
    同样的情形也会发生在对数值型字段进行计算的时候:
    SELECT * FROM inventory WHERE Amount / 7 < 24;
    SELECT * FROM inventory WHERE Amount < 24 * 7;
    
    上面的两个查询也是返回相同的结果,但后面的查询将比前面的一个快很多。第三,在搜索字符型字段时,我们有时会使用 LIKE 关键字和通配符,这种做法虽然简单,但却也是以牺牲系统性能为代价的。例如下面的查询将会比较表中的每一条记录。
    SELECT * FROM books
    WHERE name LIKE "MySQL%"
    
    但是如果换用下面的查询,返回的结果一样,但速度就要快上很多:
    SELECT * FROM books
    WHERE name >= "MySQL" AND name < "MySQM"
    
    最后,应该注意避免在查询中让 MySQL 进行自动类型转换,因为转换过程也会使索引变得不起作用。

mysql如何优化以下语句,查询耗时太久了?

根据所描述的问题,可尝试在 mms_profitcenterFOrderIDFSuffix 列上建立索引,再查询试试。下面提供 30 种 MySQL 常用优化方法供参考:

  1. 对查询进行优化,应尽量避免全表扫描,首先应考虑在 WHEREORDER BY 涉及的列上建立索引。
  2. 应尽量避免在 WHERE 子句中使用 != 或操作符,否则将引擎放弃使用索引而进行全表扫描。
  3. 应尽量避免在 WHERE 子句中对字段进行 NULL 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:
    SELECT ID FROM T WHERE NUM IS NULL
    
    可以在 NUM 上设置默认值 0,确保表中 NUM 列没有 NULL 值,然后这样查询:
    SELECT ID FROM T WHERE NUM = 0
    
  4. 应尽量避免在 WHERE 子句中使用 OR 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:
    SELECT ID FROM T WHERE NUM = 10 OR NUM = 20
    
    可以这样查询:
    SELECT ID FROM T WHERE NUM = 10
    UNION ALL
    SELECT ID FROM T WHERE NUM = 20
    
  5. 下面的查询也将导致全表扫描:
    SELECT ID FROM T WHERE NAME LIKE '%ABC%'
    
    若要提高效率,可以考虑全文检索。
  6. INNOT IN 也要慎用,否则会导致全表扫描,如:
    SELECT ID FROM T WHERE NUM IN (1, 2, 3)
    
    对于连续的数值,能用 BETWEEN 就不要用 IN 了:
    SELECT ID FROM T WHERE NUM BETWEEN 1 AND 3
    
  7. 如果在 WHERE 子句中使用参数,也会导致全表扫描。因为 SQL 只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描:
    SELECT ID FROM T WHERE NUM = @NUM
    
    可以改为强制查询使用索引:
    SELECT ID FROM T WITH(INDEX(索引名)) WHERE NUM = @NUM
    
  8. 应尽量避免在 WHERE 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:
    SELECT ID FROM T WHERE NUM / 2 = 100
    
    应改为:
    SELECT ID FROM T WHERE NUM = 100 * 2
    
  9. 应尽量避免在 WHERE 子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:
    SELECT ID FROM T WHERE SUBSTRING(NAME, 1, 3) = 'ABC' -- NAME 以 ABC 开头的 ID
    SELECT ID FROM T WHERE DATEDIFF(DAY, CREATEDATE, '2005-11-30') = 0 -- '2005-11-30' 生成的 ID
    
    应改为:
    SELECT ID FROM T WHERE NAME LIKE 'ABC%'
    SELECT ID FROM T WHERE CREATEDATE = '2005-11-30' AND CREATEDATE < '2005-12-1'
    
  10. 不要在 WHERE 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。
  11. 在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。
  12. 不要写一些没有意义的查询,如需要生成一个空表结构:
    SELECT COL1, COL2 INTO #T FROM T WHERE 1=0
    
    这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样:
    CREATE TABLE #T(...)
    
  13. 很多时候用 EXISTS 代替 IN 是一个好的选择:
    SELECT NUM FROM A WHERE NUM IN (SELECT NUM FROM B)
    
    用下面的语句替换:
    SELECT NUM FROM A WHERE EXISTS (SELECT 1 FROM B WHERE NUM = A.NUM)
    
  14. 并不是所有索引对查询都有效,SQL 是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL 查询可能不会去利用索引,如一表中有字段 SEXMALEFEMALE 几乎各一半,那么即使在 SEX 上建了索引也对查询效率起不了作用。
  15. 索引并不是越多越好,索引固然可以提高相应的 SELECT 的效率,但同时也降低了 INSERTUPDATE 的效率,因为 INSERTUPDATE 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过 6 个,若太多则应考虑一些不常使用到的列上建的索引是否有
  16. 应尽可能的避免更新 CLUSTERED 索引数据列,因为 CLUSTERED 索引数据列的顺序就是表记录的物理存储顺序,一旦该列值改变将导致整个表记录的顺序的调整,会耗费相当大的资源。若应用系统需要频繁更新 CLUSTERED 索引数据列,那么需要考虑是否应将该索引建为 CLUSTERED 索引。
  17. 尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。
  18. 尽可能的使用 VARCHAR/NVARCHAR 代替 CHAR/NCHAR,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。
  19. 任何地方都不要使用 SELECT * FROM T,用具体的字段列表代替“*”,不要返回用不到的任何字段。
  20. 尽量使用表变量来代替临时表。如果表变量包含大量数据,请注意索引非常有限(只有主键索引)。
  21. 避免频繁创建和删除临时表,以减少系统表资源的消耗。
  22. 临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用表中的某个数据集时。但是,对于一次性事件,最好使用导出表。
  23. 在新建临时表时,如果一次性插入数据量很大,那么可以使用 SELECT INTO 代替 CREATE TABLE,避免造成大量 LOG,以提高速度;如果数据量不大,为了缓和系统表的资源,应先 CREATE TABLE,然后 INSERT
  24. 如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 TRUNCATE TABLE,然后 DROP TABLE,这样可以避免系统表的较长时间锁定。
  25. 尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过 1 万行,那么就应该考虑改写。
  26. 使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方案来解决问题,基于集的方法通常更有效。
  27. 与临时表一样,游标并不是不可使用。对小型数据集使用 FAST_FORWARD 游标通常要优于其他逐行处理方法,尤其是在必须引用几个表才能获得所需的数据时。在结果集中包括“合计”的例程通常要比使用游标执行的速度快。如果开发时间允许,基于游标的方法和基于集的方法都可以尝试一下,看哪一种方法的效果更好。
  28. 在所有的存储过程和触发器的开始处设置 SET NOCOUNT ON,在结束时设置 SET NOCOUNT OFF。无需在执行存储过程和触发器的每个语句后向客户端发送 DONE_IN_PROC 消息。
  29. 尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。
  30. 尽量避免大事务操作,提高系统并发能力。