前言

之前的一篇文章介绍了索引来提高数据库的查询性能,这其实仅仅是个开始。也许假设缺乏适当的保养,索引你以前建立的,甚至成为拖累,成为帮凶下降数据库的性能。

寻找碎片

消除碎片索引维护可能是最常规的任务,,议是当碎片等级为 5% - 30% 之间时採用 REORGANIZE 来“重整”索引。假设达到 30% 以上则使用 REBUILD 来“重建”索引。决定採用何种手段和操作时机可能需要考虑很多的因素,下面4条是你必需要考虑的:

  • 备份的计划
  • server的负载
  • 磁盘剩余空间
  • 回复(Recovery) 模型

PS:尽管碎片与性能紧密相关,但某些特定情况下他能够被忽略。比方你有一张带有聚集索引的表,差点儿全部针对该表的处理不过依据主键取出一条数据。该场合下碎片的影响能够忽略不计。

那么如何确定某个索引的碎片状况呢?使用系统函数sys.dm_db_index_physical_stats 及系统文件夹 sys.Indexes。演示样例脚本例如以下:

-- 获取指定表(演示样例:ordDemo)上全部索引的信息
SELECT
sysin.name as IndexName
,sysIn.index_id
,func.avg_fragmentation_in_percent
,func.index_type_desc as IndexType
,func.page_count
FROM
sys.dm_db_index_physical_stats (DB_ID(), OBJECT_ID(N'ordDemo'), NULL, NULL, NULL) AS func
JOIN
sys.indexes AS sysIn
ON
func.object_id = sysIn.object_id AND func.index_id = sysIn.index_id -- 聚集索引的 Index_id 为 1
-- 非聚集索引为 Index_id>1
-- 下面脚本用 WHERE 子句进行了筛选(剔除了没有索引的表)
-- 该脚本返回数据库全部的索引,可能花费较长时间! SELECT
sysin.name as IndexName
,sysIn.index_id
,func.avg_fragmentation_in_percent
,func.index_type_desc as IndexType
,func.page_count
FROM
sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, NULL) AS func
JOIN
sys.indexes AS sysIn
ON
func.object_id = sysIn.object_id AND func.index_id = sysIn.index_id
WHERE sysIn.index_id>0;

输出截图例如以下

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3FsY2hlbg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

演示样例数据库的碎片为0。这是由于碎片是在运行增删改时产生的,我们的数据库还没有做过类似操作。

填充因子

前面提到过数据以8KB 数据页的方式存放在数据库中,如果你有一张建立了聚集索引的表。每当有数据插入时。数据库会依据主键找到插入位置(数据页)并写入信息。

如果该数据页已经满了或者不够空间存放新的数据,数据库会建立一个新的8KB 数据页,而这个新建的过程会造成I/O消耗。

填充因子用来降低这样的情况的发生,假设你设定填充因子为10,那么你的数据初始仅使用8KB 数据页中的10%,当插入新纪录时基本不用操心会发生多余的I/O消耗,由于数据页中预留了90%的空间。

填充因子也是把双刃剑。他在添加写操作性能的同一时候,减少了读操作的性能。

【填充因子仅当建立索引或重建(rebuildi)索引时起作用。对于一般的DML操作无效(数据页总是填充到100%)】

下面脚本帮助你了解索引的填充因子值:

SELECT
OBJECT_NAME(OBJECT_ID) AS TableName
,Name as IndexName
,Type_Desc
,Fill_Factor
FROM
sys.indexes
WHERE
-- 这里通过WHERE筛选来只表示聚集索引和非聚集索引
type_desc<>'HEAP'

你还能够查看数据server上默认的填充因子值:

SELECT
Description
,Value_in_use
FROM
sys.configurations
WHERE
Name ='fill factor (%)'

PS:0表示不保留不论什么预留空间。



通过下面脚本来设置填充因子的值:

ALTER INDEX [idx_refno] ON [ordDemo]
REBUILD WITH (FILLFACTOR= 80)
GO -- 假设要设定server上的默认值。使用下面脚本
Sp_configure 'show advanced options', 1
GO
RECONFIGURE
GO sp_configure 'fill factor', 90
GO
RECONFIGURE
GO

在一张静态表(偶然更新)的表上建议採用较大的填充因子(90%以上)。在读写频繁的表上建议採用较低的填充因子(70% - 80%)。

特别的。当你的聚集索引建立在一个自增字段上时,设定填充因子为100%也没有问题。由于新插入的数据总是在全部数据的最后,不会发生插入记录与记录之间的情况。

重建(REBUILD)索引来提高索引效率

重建索引的作用顾名思义,他带来的优点包含消除碎片,统计值(statistics)更新,数据页中物理排序顺序的对齐。另外他还会依据填充因子来压缩数据页,(假设必要的话)新增数据页。优点一箩筐,仅仅是这个操作很耗资源。会花费相当长的时间。假设你决定開始重建索引,你还须要知道他有两种工作模式:

离线模式:这是默认的重建索引模式,它将锁定表直到重建完毕。假设表非常大。会导致用户(好几个小时都)无法使用该表。相比在线模式来说离线模式工作更快,消耗的TempDb的空间更小。

在线模式:假设客观条件不同意你锁定表,你就仅仅能选择在线模式,这将耗费很多其它的时间和server资源。值得一提的是假设你的表包括了varchar (max), nvarchar (max), text 类型字段的话,将无法在该模式下进行重建索引。

【提示:该模式选择仅在开发版/企业版中支持。其它版本号默认使用离线模式。】

下面是重建索引的演示样例脚本:

-- 在线模式下重建索引 idx_refno
ALTER INDEX [idx_refno] ON [ordDemo]
REBUILD WITH (FILLFACTOR=80, ONLINE=ON)
GO -- 离线模式下重建索引 idx_refno
ALTER INDEX [idx_refno] ON [ordDemo]
REBUILD WITH (FILLFACTOR=80, ONLINE=OFF)
GO -- 重建 ordDemo 表上的全部索引
ALTER INDEX ALL ON [ordDemo]
REBUILD WITH (FILLFACTOR=80, ONLINE=OFF)
GO -- 重建索引 idx_reno (DROP_EXISTING=ON)
CREATE CLUSTERED INDEX [idx_refno] ON [ordDemo](refno)
WITH
(
DROP_EXISTING = ON,
FILLFACTOR = 70,
ONLINE = ON
)
GO -- 使用 DBCC DBREINDEX 重建 ordDemo 表上的全部索引
DBCC DBREINDEX ('ordDemo')
GO -- 使用 DBCC DBREINDEX 重建 ordDemo 表上的一个索引
DBCC DBREINDEX ('ordDemo','idx_refno',90)
GO

【DBCC DBREINDEX 将在兴许版本号被废弃】

基于作者的个人经验,在一张大数据量的表上进行重建操作时,使用批量日志恢复(bulk-logged recovery)或简单恢复(simple recovery)比較好,这能防止日志文件过大。只是须要提醒你的是,切换恢复模式时会打断数据库的备份链。所以假设你之前是全然恢复模式(full recovery),记得重建后再切换回来。

重建时一定要有耐心。长的可能花上1天,冒昧地打断他是很危急的(数据库可能进入恢复模式)。

运行该操作的用户必须是该表的全部者,或是该server的sysadmin一员,或是该数据库的db_owner / db_ddladmin。

重整(REORGANIZE)索引来提高索引效率

重整不会锁定不论什么对象。他是一个优化当前 B-Tree,组织数据页的处理及碎片整理。

重整索引处理演示样例脚本例如以下:

-- 重整 "ordDemo" 表上的 "idx_refno" 索引
ALTER INDEX [idx_refno] ON [ordDemo]
REORGANIZE
GO -- 重整 ordDemo 表上全部索引
ALTER INDEX ALL ON [ordDemo]
REORGANIZE
GO -- 重整 AdventureWorks2012 数据库中 ordDemo 表上全部索引
DBCC INDEXDEFRAG ('AdventureWorks2012','ordDemo')
GO -- 重整 AdventureWorks2012 数据库中 ordDemo 表上索引 idx_refno
DBCC INDEXDEFRAG ('AdventureWorks2012','ordDemo','idx_refno')
GO

注意:运行该操作的用户必须是该表的全部者,或是该server的sysadmin一员,或是该数据库的db_owner / db_ddladmin。

发现缺失的索引

如今你已经了解索引带来的性能提升,但实际情况下非常难在一開始就建立好足够正确及必要的索引,我们要如何才干推断出哪些表须要索引,哪些索引建立得不正确呢?

通常情况下,SQL Server 会利用既有的索引来执行查询脚本,假设没有找到索引他会自己主动生成一个并存放在DMV(dynamic management view)中。

每当SQL Server 服务重新启动的时候这些信息会被清除,所以在获取缺失索引的过程中最好保持SQL Server 服务的执行,直到全部的业务逻辑跑完一遍。

可參照下面链接来获取很多其它相关信息:

提供一个现成的脚本:

SELECT
avg_total_user_cost * avg_user_impact * (user_seeks + user_scans)
AS PossibleImprovement
,last_user_seek
,last_user_scan
,statement AS Object
,'CREATE INDEX [IDX_' + CONVERT(VARCHAR,GS.Group_Handle) + '_' +
CONVERT(VARCHAR,D.Index_Handle) + '_'
+ REPLACE(REPLACE(REPLACE([statement],']',''),'[',''),'.','') +
']'
+' ON '
+ [statement]
+ ' (' + ISNULL (equality_columns,'')
+ CASE WHEN equality_columns IS NOT NULL AND inequality_columns IS
NOT NULL THEN ',' ELSE '' END
+ ISNULL (inequality_columns, '')
+ ')'
+ ISNULL (' INCLUDE (' + included_columns + ')', '')
AS Create_Index_Syntax
FROM
sys.dm_db_missing_index_groups AS G
INNER JOIN
sys.dm_db_missing_index_group_stats AS GS
ON
GS.group_handle = G.index_group_handle
INNER JOIN
sys.dm_db_missing_index_details AS D
ON
G.index_handle = D.index_handle
Order By PossibleImprovement DESC

PS:你获取到的信息是一个提议列表,终于的决定权在你,另外DMV最多仅仅保存500个索引。

发现未使用的索引

我们建立了索引来改进性能,但假设建立的索引没有被利用到,那反而成累赘了。

与前一个小节同样的原因,保持SQL Server 服务的执行。直到全部的业务逻辑跑完一遍。执行一下脚本:

SELECT
ind.Index_id,
obj.Name as TableName,
ind.Name as IndexName,
ind.Type_Desc,
indUsage.user_seeks,
indUsage.user_scans,
indUsage.user_lookups,
indUsage.user_updates,
indUsage.last_user_seek,
indUsage.last_user_scan,
'drop index [' + ind.name + '] ON [' + obj.name + ']' as
DropIndexCommand
FROM
Sys.Indexes as ind
JOIN
Sys.Objects as obj
ON
ind.object_id=obj.Object_ID
LEFT JOIN
sys.dm_db_index_usage_stats indUsage
ON
ind.object_id = indUsage.object_id
AND
ind.Index_id=indUsage.Index_id
WHERE
ind.type_desc<>'HEAP' and obj.type<>'S'
AND
objectproperty(obj.object_id,'isusertable') = 1
AND
(isnull(indUsage.user_seeks,0) = 0
AND
isnull(indUsage.user_scans,0) = 0
AND
isnull(indUsage.user_lookups,0) = 0)
ORDER BY
obj.name,ind.Name
GO

获取这些信息后。採取如何的行动由你决定。可是当你决定删除某个索引时请注意下面两点:

  • 假设当前索引是个主键或唯一键。他能保证数据的完整性
  • 唯一索引即使本身并没有被使用,但能给优化器提供信息,从而帮助它生成更好的运行计划

建立索引视图(indexed view)来改善性能

视图是个存储的查询,表现得像表一样。它有两个主要优点:

  • 限制用户仅仅能訪问某几张表中特定字段及特定数据
  • 同意开发人员通过自己定义的方式把原始信息组织成面向用户的逻辑视图

索引视图在创建时就解析/优化好查询语句,并把相关信息以物理形式存放在数据库中。再决定使用索引视图前请考虑下面建议:

  • 视图不应该參照其它视图
  • 试图能够參照不论什么原始表
  • 字段名必须显式明白的定义好合适的别名

另外假设针对该对象的处理查询少更新多,又或者原始表是个常常更新的表,那么使用索引视图并非非常合适。

假设你有个查询包括较多的合计(aggregation)/联合(join)并且表的数据量非常大。那么能够考虑使用索引视图。使用索引视图必须设定下面參数(NUMERIC_ROUNDABORT为OFF。其余为ON)

  • ARITHABORT
  • CONCAT_NULL_YIELDS_NULL
  • QUOTED_IDENTIFIER
  • ANSI_WARNINGS
  • ANSI_NULLS
  • ANSI_PADDING
  • NUMERIC_ROUNDABORT

演示样例脚本:

CREATE VIEW POView
WITH SCHEMABINDING
AS
SELECT
POH.PurchaseOrderID
,POH.OrderDate
,EMP.LoginID
,V.Name AS VendorName
,SUM(POD.OrderQty) AS OrderQty
,SUM(POD.OrderQty*POD.UnitPrice) AS Amount
,COUNT_BIG(*) AS Count
FROM
[Purchasing].[PurchaseOrderHeader] AS POH
JOIN
[Purchasing].[PurchaseOrderDetail] AS POD
ON
POH.PurchaseOrderID = POD.PurchaseOrderID
JOIN
[HumanResources].[Employee] AS EMP
ON
POH.EmployeeID=EMP.BusinessEntityID
JOIN
[Purchasing].[Vendor] AS V
ON
POH.VendorID=V.BusinessEntityID
GROUP BY
POH.PurchaseOrderID
,POH.OrderDate
,EMP.LoginID
,V.Name
GO -- 在视图上建立一个聚集索引使得它成为使得它成为索引视图
CREATE UNIQUE CLUSTERED INDEX IndexPOView ON POView
(PurchaseOrderID)
GO

你能够对照一下查询语句与查询索引视图的运行计划,索引视图的方式提供了更好的查询性能:

SQL Server 的查询优化器总是尝试找到最佳的运行计划,有时候尽管你建立了索引视图,但优化器依旧使用了原始表上的索引,此时你能够使用 WITH NOEXPAND 来强制使用索引视图上的索引(而不是原始表上的索引)。

索引视图在 SQL Server 2012 的各个版本号上都有支持。在开发版或企业版中查询处理器甚至能以此来把匹配索引视图的查询都优化了。

索引视图建立时必须带上 WITH SCHEMABINDING,以此保证用到的字段不会被改动掉。

假设索引视图包括了 GROUP BY 子句,则必须在 SELECT 子句中包括 COUNT_BIG (*),而且不能指定 HAVING, CUBE, 以及 ROLLUP。

使用计算字段(Computed Columns)上的索引来改善性能

首先来介绍一下计算字段(Computed Columns)。它通过一个表达式来引用同一张表的其它字段,然后运算出一个结果。

这个字段的值会在每次被调用时都又一次计算。除非你在建立时带上 PERSISTED 标记。

在决定是否在计算字段上建立索引前,须要考虑一下几点:

  • 计算字段为 Image, Text, 或 ntext 的情况,它仅仅能作为非聚集索引的非keyword段(non-key column)
  • 计算字段表达式不能是 REAL 或 FLOAT 类型
  • 计算字段应当是精确的(?)
  • 计算字段应当是确定的(输入同样的值,输出同样的结果)
  • 计算字段假设使用了函数(function)。无论是用户函数还是系统函数,表及函数的拥有者必须是同一个
  • 针对多行记录的函数(比方:SUM, AVG)不能在计算字段中使用
  • 增删改会改变计算字段上索引的值,所以必须设定下面6个參数。

SET ANSI_NULLS ON

SET ANSI_PADDING ON

SET ANSI_WARNINGS ON

SET ARITHABORT ON

SET CONCAT_NULL_YIELDS_NULL ON

SET QUOTED_IDENTIFIER ON

SET NUMERIC_ROUNDABORT OFF

以下我们来看一个完整的样例:

1. 设定系统变量,并建立我们的測试数据表

SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
SET ARITHABORT ON
SET CONCAT_NULL_YIELDS_NULL ON
SET QUOTED_IDENTIFIER ON
SET NUMERIC_ROUNDABORT OFF SELECT
[SalesOrderID]
,[SalesOrderDetailID]
,[CarrierTrackingNumber]
,[OrderQty]
,[ProductID]
,[SpecialOfferID]
,[UnitPrice]
INTO
SalesOrderDetailDemo
FROM
[AdventureWorks2012].[Sales].[SalesOrderDetail]
GO

2. 建立一个用户自己定义函数。然后再建立一个计算字段并使用这个函数

CREATE FUNCTION
[dbo].[UDFTotalAmount] (@TotalPrice numeric(10,3), @Freight
TINYINT)
RETURNS Numeric(10,3)
WITH SCHEMABINDING
AS
BEGIN
DECLARE @NetPrice Numeric(10,3)
SET @NetPrice = @TotalPrice + (@TotalPrice*@Freight/100)
RETURN @NetPrice
END
GO
--adding computed column SalesOrderDetailDemo table
ALTER TABLE SalesOrderDetailDemo
ADD [NetPrice] AS [dbo].[UDFTotalAmount] ( OrderQty*UnitPrice,5)
GO

3. 建立一个聚集索引。打开性能指标开关,并运行一条查询(注意此时我们还没有在计算字段上建立索引。)

CREATE Clustered Index idx_SalesOrderID_SalesOrderDetailID_
SalesOrderDetailDemo
ON SalesOrderDetailDemo(SalesOrderID,SalesOrderDetailID)
GO
--checking SalesOrderDetailDemo with statistics option ON to
--measure performance
SET STATISTICS IO ON
SET STATISTICS TIME ON
GO
--checking SELECT statement without having Index on Computed
Column
SELECT * FROM SalesOrderDetailDemo WHERE NetPrice>5000
GO

输出的性能结果例如以下:

SQL Server parse and compile time:

    CPU time = 650 ms, elapsed time = 650 ms.

SQL Server parse and compile time:

    CPU time = 0 ms, elapsed time = 0 ms.



(3864 row(s) affected)



Table 'SalesOrderDetailDemo'. Scan count 1, logical reads 757,

physical reads 0, read-ahead reads 0, lob logical reads 0, lob

physical reads 0, lob read-ahead reads 0.



SQL Server Execution Times:

    CPU time = 562 ms, elapsed time = 678 ms.

4. 在计算字段上建立索引之前,能够用下面的脚本确认是否满足之前提到的创建要求:(返回值:0不满足。1满足)

SELECT
COLUMNPROPERTY( OBJECT_ID('SalesOrderDetailDemo'),'NetPrice','IsIndexable') AS 'Indexable?'
,COLUMNPROPERTY( OBJECT_ID('SalesOrderDetailDemo'),'NetPrice','IsDeterministic') AS 'Deterministic? '
,OBJECTPROPERTY(OBJECT_ID('UDFTotalAmount'),'IsDeterministic')'UDFDeterministic?'
,COLUMNPROPERTY(OBJECT_ID('SalesOrderDetailDemo'),'NetPrice','IsPrecise') AS 'Precise? '

5. 满足要求的情况下建立索引。并再次运行先前的查询语句

CREATE INDEX idx_SalesOrderDetailDemo_NetPrice
ON SalesOrderDetailDemo
(
NetPrice
)
GO SELECT * FROM SalesOrderDetailDemo WHERE NetPrice>5000
GO

这次的性能结果例如以下:

SQL Server parse and compile time:

    CPU time = 0 ms, elapsed time = 0 ms.

SQL Server parse and compile time:

    CPU time = 0 ms, elapsed time = 0 ms.



(3864 row(s) affected)



Table 'SalesOrderDetailDemo'. Scan count 1, logical reads 757,

physical reads 0, read-ahead reads 0, lob logical reads 0, lob

physical reads 0, lob read-ahead reads 0.



SQL Server Execution Times:

    CPU time = 546 ms, elapsed time = 622 ms.

确认索引占用的磁盘空间

SELECT
CASE index_id
WHEN 0 THEN 'HEAP'
WHEN 1 THEN 'Clustered Index'
ELSE 'Non-Clustered Index'
END AS Index_Type,
SUM(CASE
WHEN FilledPage > PageToDeduct THEN (FilledPage-PageToDeduct)
ELSE
0
END )* 8 Index_Size
FROM
(
SELECT
partition_id,
index_id,
SUM (used_page_count) AS FilledPage,
SUM (
CASE
WHEN (index_id < 2) THEN (in_row_data_page_count + lob_used_page_count + row_overflow_used_page_count)
ELSE
lob_used_page_count + row_overflow_used_page_count
END
) AS PageToDeduct
FROM
sys.dm_db_partition_stats
GROUP BY
partition_id,index_id
) AS InnerTable
GROUP BY
index_id
GO

PS: 输出的单元KB

SQL Server 性能优化3 该指数(Index)保养的更多相关文章

  1. SQL Server性能优化(6)查询语句建议

    1. 如果对数据不是工业级的访问(允许脏读),在select里添加 with(nolock) ID FROM Measure_heat WITH (nolock) 2. 限制结果集的数据量,如使用TO ...

  2. SQL SERVER性能优化综述

    SQL SERVER性能优化综述 一个系统的性能的提高,不单单是试运行或者维护阶段的性能调优的任务,也不单单是开发阶段的事情,而是在整个软件生命周期都需要注意,进行有效工作才能达到的.所以我希望按照软 ...

  3. 【SQL Server性能优化】删除大量数据的方法比较

    原文:[SQL Server性能优化]删除大量数据的方法比较 如果你要删除表中的大量数据,这个大量一般是指删除大于10%的记录,那么如何删除,效率才会比较高呢? 而如何删除才会对系统的影响相对较小呢? ...

  4. 【SQL Server性能优化】运用SQL Server的全文检索来提高模糊匹配的效率

    原文:[SQL Server性能优化]运用SQL Server的全文检索来提高模糊匹配的效率 今天去面试,这个公司的业务需要模糊查询数据,之前他们通过mongodb来存储数据,但他们说会有丢数据的问题 ...

  5. SQL Server 性能优化(一)——简介

    原文:SQL Server 性能优化(一)--简介 一.性能优化的理由: 听起来有点多余,但是还是详细说一下: 1.节省成本:这里的成本不一定是钱,但是基本上可以变相认为是节省钱.性能上去了,本来要投 ...

  6. SQL Server 性能优化之——系统化方法提高性能

    SQL Server 性能优化之——系统化方法提高性能 阅读导航 1. 概述 2. 规范逻辑数据库设计 3. 使用高效索引设计 4. 使用高效的查询设计 5. 使用技术分析低性能 6. 总结 1. 概 ...

  7. SQL Server性能优化与管理的艺术 附件下载地址

    首先感谢读者们对鄙人的支持,购买了<SQL Server性能优化与管理的艺术>,由于之前出版社的一些疏忽,附件没有上传成功,再次本人深表歉意. 请需要下载附件的读者从下面链接下载,谢谢: ...

  8. SQL Server 性能优化之RML Utilities:快速入门(Quick Start)(1)

      SQL Server 性能优化之RML Utilities:快速入门(Quick Start)(1) 安装Quick Start工具 RML(Replay Markup Language)是MS ...

  9. SQL Server 性能优化详解

    故事开篇:你和你的团队经过不懈努力,终于使网站成功上线,刚开始时,注册用户较少,网站性能表现不错,但随着注册用户的增多,访问速度开始变慢,一些用户开始发来邮件表示抗议,事情变得越来越糟,为了留住用户, ...

随机推荐

  1. 2434: [Noi2011]阿狸的打字机

    ac自动机,bit,dfs序. 本文所有的stl都是因为自己懒得实现.   首先x在y里面出现,就意味y节点可以顺着fail回去. 反向建出一个fail数,然后搞出dfs序列.找出x对应的区间有多少个 ...

  2. jquery 分页控件(一)

    以前一直都是用别人的分页控件,虽然用得很爽,但总觉的还是自己写个小插件比较好,这个插件效果.代码等都有参照别人完成的控件.即便功能并不是那么完善,扩展性也不好,bug或许还很多.个人觉得,适合自己用就 ...

  3. ZJOI2010网络扩容

    无限orz hzwer神牛…… 第一问很简单,按数据建图,然后一遍最大流算法即可.     第二问则需要用最小费用最大流算法,主要是建图,那么可以从第一问的残留网络上继续建图,对残留网络上的每一条边建 ...

  4. 几款JS地图插件比较

    因工作需要,最近研究几款关于地图的JS插件,现与大家分享一下. 以下比较只是浅层次的分析一下,并没有实际通过项目检验,所以不足之处还请大家指出. 地图插件对比 插件名  简介 区域支持 扩展性 离线支 ...

  5. urllib

    urllib Python 标准库 urllib2 的使用细节 python 2.x 3.x from urllib import request with request.urlopen('http ...

  6. 【jQuery】

    TryjQuery:jQuery官方推出的教学视频http://blog.jobbole.com/37699/ jQuery 1.11 / 2.1 beta 版发布,全面支持异步模块加载  √http ...

  7. boostrap兼容ie及其案例

    多梦网络 wordpress主题 http://www.dmeng.net/

  8. keybd_event跟SendMessage,PostMessage模拟键盘消息的区别 z

    首先你会发现keybd_event函数中是没有窗口句柄作为参数的,好奇的你一定会觉得很奇怪,那是因为,keybd_event是全局模拟按键的,只对前台窗口(即当前的活动窗口)才可以,但是如果模拟的按键 ...

  9. lightoj 1014

    判断到根号n即可,另外使用dfs输出,不需要另开数组再排序. #include<cmath> #include<cstdio> int P, L, len, cnt; void ...

  10. Her and his blog

    Tonight, I read localhost8080 and some of her husband m67's blog. I found they are so geek and reall ...