mysql使用explain优化,以及索引的建立

通过使用explain来优化sql,对于基础的项目来说,访问速度慢的主要原因几乎上都是sql语句,或者有垃圾代码,导致了很多不必要的计算或者查询。我们可以通过explain选择更好的索引写出速度更快的查询语句。

使用explain分析sql,会输出分析结果,例如:

1
explain SELECT `products`.* FROM `products` WHERE `products`.`state` = 1 AND `products`.`catalog_id` = 335 AND `products`.`sell` = 1 ORDER BY priority desc limit 20


介绍一下各列的意义,其中:

  1. id列数字越大越先执行,如果说数字一样大,那么就从上往下依次执行,id列为null的就表示这是一个结果集,不需要使用它来进行查询。
  2. select_type,select类型,它有以下几种值
    2.1:simple:表示不需要union操作或者不包含子查询的简单select查询。有连接查询时,外层的查询为simple,且只有一个
    2.2:primary:一个需要union操作或者含有子查询的select,位于最外层的单位查询的select_type即为primary。且只有一个
    2.3:union:union连接的两个select查询,第一个查询是dervied派生表,除了第一个表外,第二个以后的表select_type都是union
    2.4:dependent union:与union一样,出现在union 或union all语句中,但是这个查询要受到外部查询的影响
    2.5:union result:包含union的结果集,在union和union all语句中,因为它不需要参与查询,所以id字段为null
    F:subquery:除了from字句中包含的子查询外,其他地方出现的子查询都可能是subquery
    2.6:dependent subquery:与dependent union类似,表示这个subquery的查询要受到外部表查询的影响
    2.7:derived:from字句中出现的子查询,也叫做派生表,其他数据库中可能叫做内联视图或嵌套select

mac配置php环境

要帮同学搭一个网站,发现网上php这类的源码比较多,找了一个项目的源码,就想搭一个环境跑一下试试(其实我内心是想用rails的,奈何源码不好找,姑且就先用php试一下)。
OSX下自带php的环境,可通过查看版本

1
2
$ php -v
PHP 5.5.36 (cli)

启动Apache

1
$ apachectl start

浏览器通过访问 http://localhost 应该就可以看到欢迎页面,如果访问不到,可以通过命令

1
$ apachectl configtest

来检查配置文件是否有误,如果有误,根据提示来修改配置文件,直到返回

1
$ Syntax OK

然后在访问 http://localhost 应该就可以看到欢迎页面了,默认的项目路径在

1
$ /Library/WebServer/Documents

接下来我们要配置一下php的配置文件,养成一个好习惯,修改配置文件之前先做备份,以备后用

rails_devise_warden_登陆解析

devise是rails用的比较多的一个用户登陆注册模块,研究了下他的登陆以及验证的策略(虽说还没有完全吃透),先记录下。
devise的具体使用可以参照他的文档
devise的认证机制是基于warden,所以要先了解一下warden才能理解。用户名以及密码的验证我们这里暂且不提,主要看一下sign_in方法做了什么,以及登陆之后下次请求是如何把已登录的信息带过来验证的。
1.先看下sign_in方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def sign_in(resource_or_scope, *args)
options = args.extract_options!
scope = Devise::Mapping.find_scope!(resource_or_scope)
resource = args.last || resource_or_scope
expire_data_after_sign_in!
if options[:bypass]
warden.session_serializer.store(resource, scope)
elsif warden.user(scope) == resource && !options.delete(:force)
# Do nothing. User already signed in and we are not forcing it.
true
else
warden.set_user(resource, options.merge!(scope: scope))
end
end

warden.session.store方法,会把user id存入env[‘rack.session’][‘warden.user.user.key’]中

1
2
3
4
5
6
7
8
9
10
11
12
13
# gems/warden-1.2.3/lib/warden/session_serializer.rb
def store(user, scope)
return unless user
method_name = "#{scope}_serialize"
specialized = respond_to?(method_name)
session[key_for(scope)] = specialized ? send(method_name, user) : serialize(user)
end
#gems/warden-1.2.3/lib/warden/manager.rb
def serialize_into_session(scope = nil, &block)
method_name = scope.nil? ? :serialize : "#{scope}_serialize"
Warden::SessionSerializer.send :define_method, method_name, &block
end

2.已登陆成功之后,通过authenticate_user! 来验证是否登陆

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def self.define_helpers(mapping) #:nodoc:
mapping = mapping.name
class_eval <<-METHODS, __FILE__, __LINE__ + 1
def authenticate_#{mapping}!(opts={})
opts[:scope] = :#{mapping}
warden.authenticate!(opts) if !devise_controller? || opts.delete(:force)
end
def #{mapping}_signed_in?
!!current_#{mapping}
end
def current_#{mapping}
@current_#{mapping} ||= warden.authenticate(scope: :#{mapping})
end
def #{mapping}_session
current_#{mapping} && warden.session(:#{mapping})
end
METHODS
ActiveSupport.on_load(:action_controller) do
helper_method "current_#{mapping}", "#{mapping}_signed_in?", "#{mapping}_session"
end
end
#["/Users/.rvm/gems/ruby-2.3.0/gems/warden-1.2.3/lib/warden/proxy.rb", 103]
[查看此文件可知](https://github.com/hassox/warden/blob/master/lib/warden/proxy.rb)最后是通过获取env["rack.session"]['warden.user.user.key']来获取到当前登陆的用户的

Tips:

查看一个方法调用的位置:

method(:sign_in)
# ["/Users/.rvm/gems/ruby-2.3.0/gems/devise-3.4.1/lib/devise/controllers/sign_in_out.rb", 30]
warden.session_serializer.method(:store).source_location
# ["/Users/.rvm/gems/ruby-2.3.0/gems/warden-1.2.3/lib/warden/session_serializer.rb", 22]

参考文档

warden wiki
warden源码解析
rack中间件warden的机制
rack安全

rails_import_xls_and_csv

项目中经常会遇到需要导入excel以及csv等文件格式的数据到数据库中。
1.导入xls文件,文档
添加gem

1
gem 'spreadsheet', '1.0.0'

导入的只能是xls格式的,如果为xlsx格式的需要先手动转化为xls格式在进行导入,直接在rails c 中读取文件,然后操作

1
2
3
4
5
book = Spreadsheet.open('public/a.xls'); #如果是在rails c中直接读取的时候,最后记得加上分号,如果不加分号会全部读取,要等很长时间
sheet = book.worksheet 0 #后面的数字是代表读取那个工作区间的
sheet.each_with_index do |row, index|
p row[0] #index为行数 row为具体行里的内容,row[0]指的是取出第一列
end

2.导出xls文件

1
2
3
4
5
6
7
8
xls_report = StringIO.new
Spreadsheet.client_encoding = 'UTF-8'
book = Spreadsheet::Workbook.new
sheet1 = book.create_worksheet name: '测试' #工作区
sheet1.row(0).concat([第一列,第二列])
sheet1[1,0] = 'china'
sheet1.column(0).default_format = Spreadsheet::Format.new align: :right,weight: :bold #局右加粗
book.write xls_report #保存