mysql-使用联合索引
背景
项目使用mysql数据库,某张表数据量2000W左右,比较大,在组合查询时发生超时,需要优化。
优化
查询优化常用方法就是建立索引
查询语句样例:查询在20181001-20181010时间范围内A=a且B=b的数据
select * from table where A = 'a' and B = 'b' and Date > '20181001' and Date < '20181010'
按照查询建立了一个组合索引 idx_query(A, B, Date),查询仍然报超时。然后开始研究索引原理,最后更改索引中列的顺序为idx_query(B,A,Date)解决。
---------------------------------------------------------------------------------------------
上面只是简单的项目背景,下面从原理细细解读索引
索引原理
首先,出问题以后再建立索引,是一种不好的习惯。排查、定位、解决问题会耗费很多开发时间和精力。
当然,不充分思考就给大多数列建立单列索引,给所有查询建立联合索引,是一种更坏的习惯。毕竟删除索引风险远高于添加索引。
使用索引需要成本:
- 空间成本:索引是占空间的,大表的联合索引占用空间不可忽略
- 时间成本:使用不对的索引会浪费时间
- 更新成本:增删改操作只要跟索引有关系,就需要更新索引
索引适合在返回大表中很小一部分数据时使用,很小当然越小越好,5%以下还可以,1%以下更好,如果表的数据量非常大,千万级别,返回行数要小到0.1%以下
从很大表中用联合条件查询出很小的数据,等价于count(distinct 联合条件) 的值很大,这个值被称为Cardinality,索引适合度=Cardinality/表记录数。
索引误区
多个单列索引(如idx_A, idx_B)不等同于联合索引(idx_A_B)
两个联合索引里的列顺序不同,这两个联合索引也不等价,适用场景不同
联合索引idx_A_B能够覆盖的场景
- A = ? and B = ?
- A = ? and B in (?, ?, ?)
- A = ?
- A in (?,?,?)
覆盖场景可以根据索引存储结构(B+Tree)推导出。
上面罗列的几种覆盖场景,效率由上至下越来越低,因为扫描行数越来越大
联合条件中,最左侧的索引列很重要,最好使用Cardinality最大的列。
总结
项目中遇到的问题,最终根据索引原理中 最左侧索引列使用Cardinality最大列 解决。
解决Raspberry PI Zero W中Lua使用lua-periphery与Python中设置的GPIO端口不一致的问题
在树莓派实时系统下脚本语言的选择(应当使用Lua而不是Python)中,我们没有使用rpi-gpio,而是使用了lua-periphery来解决Lua语言下操作树莓派GPIO的问题。
当时选择lua-periphery的原因在于rpi-gpio在Raspberry PI Zero W中使用的时候会崩溃。这个原因是在于cpuinfo.c这个文件中缺少对于BCM2835这颗新的CPU的判断,只判断了BCM2708(估计写这个库的时候,只有BCM2708)。导致RPi_GPIO_Lua_module.c在初始化GPIO的时候抛出了异常。这个已经有人提交了代码合并请求,估计很快会修复。
但是在lua-periphery中,没有对于GPIO进行重新映射,导致跟rpi-gpio以及树莓派自带的Python库在设置GPIO的时候,端口号对应不一致。比如,在Python中设置GPIO 22,执行命令观察ls /sys/class/gpio/,会发现系统创建的是GPIO 25这个对应关系就是通过查表获取的。如下图:
继续阅读解决Raspberry PI Zero W中Lua使用lua-periphery与Python中设置的GPIO端口不一致的问题
解决Raspberry Pi安装libgtk2.0-dev出错的问题
最近在树莓派上需要安装libgtk2.0-dev,执行如下命令:
|
1 |
$ sudo apt-get install libgtk2.0-dev |
出错信息如下:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
Reading package lists... Done Building dependency tree Reading state information... Done Some packages could not be installed. This may mean that you have requested an impossible situation or if you are using the unstable distribution that some required packages have not yet been created or been moved out of Incoming. The following information may help to resolve the situation: The following packages have unmet dependencies: libgtk2.0-dev : Depends: libpango1.0-dev (>= 1.20) but it is not going to be installed Depends: libcairo2-dev (>= 1.6.4-6.1) but it is not going to be installed E: Unable to correct problems, you have held broken packages. |
根据出错信息,明显是软件源中出现了安装包缺失的问题。这个现象是不应该出现的。网上查询了不少地方,最终找到解决方法:
|
1 |
$ sudo vim /etc/apt/sources.list.d/raspi.list |
可以看到如下内容:
|
1 2 3 |
#deb http://archive.raspberrypi.org/debian/ stretch main ui staging # Uncomment line below then 'apt-get update' to enable 'apt-get source' #deb-src http://archive.raspberrypi.org/debian/ stretch main ui |
默认里面的内容都是被注释掉的,我们需要做的就是把这个源打开即可。
也可以直接执行如下命令来开启:
|
1 2 3 4 |
#先备份配置文件 $ sudo cp /etc/apt/sources.list.d/raspi.list /etc/apt/sources.list.d/raspi.list.bak $ sudo sed -i "s/^\#deb/deb/g" /etc/apt/sources.list.d/raspi.list |
参考链接
修正ubuntu 18.04上执行"sudo apt upgrade"报告"libc6-dev-armhf-cross"升级出错
最近自己电脑上的ubuntu 18.04在更新软件的时候报告如下错误信息:
|
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 26 27 |
$ sudo apt upgrade 正在读取软件包列表... 完成 正在分析软件包的依赖关系树 正在读取状态信息... 完成 正在计算更新... 完成 下列软件包将被升级: libc6-armhf-cross libc6-dev-armhf-cross 升级了 2 个软件包,新安装了 0 个软件包,要卸载 0 个软件包,有 0 个软件包未被升级。 需要下载 0 B/2,904 kB 的归档。 解压缩后会消耗 0 B 的额外空间。 您希望继续执行吗? [Y/n] (正在读取数据库 ... 系统当前共安装有 239272 个文件和目录。) 正准备解包 .../libc6-dev-armhf-cross_2.27-3ubuntu1cross1.1_all.deb ... 正在将 libc6-dev-armhf-cross (2.27-3ubuntu1cross1.1) 解包到 (2.27-3ubuntu1cross1) 上 ... dpkg: 处理归档 /var/cache/apt/archives/libc6-dev-armhf-cross_2.27-3ubuntu1cross1.1_all.deb (--unpack)时出错: 无法打开 /usr/arm-linux-gnueabihf/lib/Mcrt1.o.dpkg-new : 没有那个文件或目录 错误信息显示本地系统有一些问题,因此没有写入 apport 报告 正准备解包 .../libc6-armhf-cross_2.27-3ubuntu1cross1.1_all.deb ... 正在将 libc6-armhf-cross (2.27-3ubuntu1cross1.1) 解包到 (2.27-3ubuntu1cross1) 上 ... dpkg: 处理归档 /var/cache/apt/archives/libc6-armhf-cross_2.27-3ubuntu1cross1.1_all.deb (--unpack)时出错: 无法打开 /usr/arm-linux-gnueabihf/lib/ld-2.27.so.dpkg-new : 没有那个文件或目录 错误信息显示本地系统有一些问题,因此没有写入 apport 报告 在处理时有错误发生: /var/cache/apt/archives/libc6-dev-armhf-cross_2.27-3ubuntu1cross1.1_all.deb /var/cache/apt/archives/libc6-armhf-cross_2.27-3ubuntu1cross1.1_all.deb E: Sub-process /usr/bin/dpkg returned an error code (1) |
如果系统语言为英文,则错误信息如下:
|
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 26 |
$ sudo apt upgrade Reading package lists... Done Building dependency tree Reading state information... Done Calculating upgrade... Done The following packages will be upgraded: libc6-armhf-cross libc6-dev-armhf-cross 2 upgraded, 0 newly installed, 0 to remove and 0 not upgraded. Need to get 0 B/2,904 kB of archives. After this operation, 0 B of additional disk space will be used. Do you want to continue? [Y/n] (Reading database ... 239272 files and directories currently installed.) Preparing to unpack .../libc6-dev-armhf-cross_2.27-3ubuntu1cross1.1_all.deb ... Unpacking libc6-dev-armhf-cross (2.27-3ubuntu1cross1.1) over (2.27-3ubuntu1cross1) ... dpkg: error processing archive /var/cache/apt/archives/libc6-dev-armhf-cross_2.27-3ubuntu1cross1.1_all.deb (--unpack): unable to open '/usr/arm-linux-gnueabihf/lib/Mcrt1.o.dpkg-new': No such file or directory No apport report written because the error message indicates an issue on the local system Preparing to unpack .../libc6-armhf-cross_2.27-3ubuntu1cross1.1_all.deb ... Unpacking libc6-armhf-cross (2.27-3ubuntu1cross1.1) over (2.27-3ubuntu1cross1) ... dpkg: error processing archive /var/cache/apt/archives/libc6-armhf-cross_2.27-3ubuntu1cross1.1_all.deb (--unpack): unable to open '/usr/arm-linux-gnueabihf/lib/ld-2.27.so.dpkg-new': No such file or directory No apport report written because the error message indicates an issue on the local system Errors were encountered while processing: /var/cache/apt/archives/libc6-dev-armhf-cross_2.27-3ubuntu1cross1.1_all.deb /var/cache/apt/archives/libc6-armhf-cross_2.27-3ubuntu1cross1.1_all.deb E: Sub-process /usr/bin/dpkg returned an error code (1) |
解决方法为卸载后重新安装,而不使用升级安装:
|
1 2 3 |
$ sudo apt remove libc6-dev-armhf-cross $ sudo apt install libc6-dev-armhf-cross |
参考链接
How do I fix an error with libc6-dev-armhf-cross in Ubuntu 18.04 when trying to apt upgrade?
Lua的集成开发环境ZeroBrane Studio
Lua进行脚本的开发,可是官方并没有提供很好的集成开发环境。体验了很多,发现
ZeroBrane Studio这个开源软件还是非常好用的,并且已经能正常支持Linux,Windows,MacOS这三个主流平台。
建议去官方网站下载最新的版本,但是鉴于国内网络访问不是非常稳定,可以从本站下载一份目前最新的版本。
下面的版本根据自身操作系统来选择其中一个进行下载
ZeroBraneStudioEduPack-1.70-linux.sh
ZeroBraneStudioEduPack-1.70-macos.dmg
ZeroBraneStudioEduPack-1.70-win32.exe
树莓派下的编译(目前编译出的暂时无法使用):
|
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
$ git clone https://github.com/pkulchenko/ZeroBraneStudio.git #如果代码下载存在问题,可以本站下载一份拷贝 # wget https://www.mobibrw.com/wp-content/uploads/2018/09/ZeroBraneStudio.tar.xz # tar xvf ZeroBraneStudio.tar.xz $ cd ZeroBraneStudio $ cd build $ bash build-linux-prep-deb.sh # gthread $ sudo apt-get install libglib2.0-dev # gtk+ $ sudo apt-get install libgtk2.0-dev $ sudo apt-get install libgtk-3-dev #opengl $ sudo apt-get install freeglut3-dev # ssl for luasec $ sudo apt-get install libssl-dev $ sudo ln -s /usr/lib/arm-linux-gnueabihf/libssl.so /usr/lib/libssl.so # lua $ sudo apt-get install lua5.1 liblua5.1-dev #webview可选 #sudo apt-get install libwebkitgtk-dev # luasec最新版本,早期版本编译不通过 $ sed -i "s/^LUASEC_BASENAME=\"luasec-0.6\"/LUASEC_BASENAME=\"luasec-0.7\"/g" build-linux.sh #此处wxWidgets的克隆比较慢,因此可以本站下载一份拷贝,手工修改脚本的下载 # wget https://www.mobibrw.com/wp-content/uploads/2018/09/wxWidgets.tar.xz # sed -i "s/^[ \t]*git clone \"\$WXWIDGETS_URL\".*/ wget https:\/\/www.mobibrw.com\/wp-content\/uploads\/2018\/09\/wxWidgets.tar.xz\n rm -rf wxWidgets\n tar xvf wxWidgets.tar.xz/g" build-linux.sh # wget # sed -i "s/^[ \t]*git clone \"\$WXLUA_URL\" \"\$WXLUA_BASENAME\".*/ wget https:\/\/www.mobibrw.com\/wp-content\/uploads\/2018\/09\/wxlua.tar.xz\n rm -rf wxlua\n tar xvf wxlua.tar.xz/g" build-linux.sh # sed -i "s/^LEXLPEG_URL=\"https:\/\/foicica.com\/scintillua\/download/LEXLPEG_URL=\"https:\/\/www.mobibrw.com\/wp-content\/uploads\/2018\/09/g" build-linux.sh # for debug "bash build-linux.sh debug all" $ bash build-linux.sh all #编译两次,解决第一次的问题,第一次有些目录创建存在问题 $ bash build-linux.sh all #还是需要安装一些依赖,上面编译的库并没有完整完成依赖设置 $ sudo apt-get install luarocks $ sudo luarocks install luasocket $ cp deps/lib/libwx.so deps/lib/wx.so #动态链接库应当设置LUA_CPATH而不是LUA_PATH $ export LUA_CPATH="`pwd`/deps/lib/?.so;`pwd`/deps/lib/lua/51/?.so" $ export LD_LIBRARY_PATH=`pwd`/deps/lib #去掉两个检测,这两检测总是会失败,原因不好排查 $ sed -i "s/check_lua_module(wx TRUE)/#check_lua_module(wx TRUE)/g" CMakeLists.txt $ sed -i "s/check_lua_module(socket TRUE)/#check_lua_module(socket TRUE)/g" CMakeLists.txt $ cmake -DCMAKE_SYSROOT=`pwd`/deps/ -DCMAKE_FIND_ROOT_PATH=`pwd`/deps/ . $ make $ sudo make install |
参考链接
Debugging Lua Code
Lightweight IDE for your Lua needs ZeroBrane Studio
解决Raspberry Pi Zero W启动后没有在HDMI口输出内容的问题
最新在使用的Raspberry Pi Zero W V1.3在使用目前(2018.09.26)的系统的时候发现无法正常输出内容到屏幕上面,屏幕一直黑屏无信号。
原因在于Raspberry Pi Zero W在启动的时候没有正确检测到屏幕信号,导致没有正常输出。
解决方法是打开启动配置文件/boot/config.txt, 找到如下内容:
|
1 2 3 4 5 6 |
.................. # uncomment if hdmi display is not detected and composite is being output #hdmi_force_hotplug=1 ................. |
然后去掉注释,修改为如下:
|
1 2 |
# uncomment if hdmi display is not detected and composite is being output hdmi_force_hotplug=1 |
树莓派实时系统下脚本语言的选择(应当使用Lua而不是Python)
最近在使用树莓派与其他设备通过SPI接口进行通信,使用一个GPIO管脚触发读取数据的信号,为了简化开发,使用了Python。
在实际运行过程中,发现当长时间运行的是,会出现中断管脚信号丢失的情况,在参考 Ubuntu 16.04 (x64)下从源代码为Raspberry Pi Zero W编译实时内核 更换为实时内核之后,短时间运行已经可以正常,但是在十几个小时之后,依然出现了中断丢失的现象。
这个现象初步评估为Python的GC动作时间过长导致的中断信号丢失。Python本身并不是为实时系统设计的,因此在GC进行垃圾回收的时候,是没有实时性的考虑的,因此在严格要求实时性的系统环境下,不是非常的合适。更何况很多的IO操作默认都是阻塞的,更加容易导致实时性问题。
由于树莓派本身也是支持Lua脚本的,默认安装的Lua引擎默认是5.1.4。Lua本身在游戏中使用较多,而游戏本身对于实时性的要求是很高的。
尤其是Lua 5.1开始使用最新的GC已经能很好的解决实时性问题。
关于Lua的GC相关信息,参考如下的文章:
Ubuntu 16.04 (x64)下从源代码为Raspberry Pi Zero W编译实时内核
首先参考 Ubuntu 16.04 (x64)树莓派B+ (Raspberry Pi B+)源代码编译 保证能够成功编译标准内核的源代码,然后切换到实时内核分支,并执行如下编译命令:
|
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 26 27 28 29 30 31 |
$ export PATH=$PATH:~/rpi/rpi-tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin $ cd ~/rpi/rpi-linux/ $ git checkout rpi-4.14.y-rt $ git reset --hard $ KERNEL=kernel $ make clean $ make mrproper $ rm -rf .config #调整内核切换频率,增加实时性 $ sed -i '$a\CONFIG_HZ_1000=y' arch/arm/configs/bcmrpi_defconfig #Raspberry Pi Zero W的CPU是BCM2835 $ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcmrpi_defconfig $ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage modules dtbs -j8 $ mkdir rt_kernel $ make modules_install ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=./rt_kernel -j8 $ make dtbs_install ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_DTBS_PATH=./rt_kernel -j8 $ ./scripts/mkknlimg ./arch/arm/boot/zImage ./rt_kernel/kernel.img |
安装编译好的内核
Ubuntu下面,SD卡会自动挂载,默认挂载到了/media/目录下面,如果是使用NOOBS安装的话,系统目录是固定的,执行如下命令拷贝到目标SD卡上面
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
$ cd ~/rpi/rpi-linux #备份需要修改的文件 $ mv /media/`whoami`/boot/kernel.img /media/`whoami`/boot/kernel_old.img $ mv /media/`whoami`/boot/overlays /media/`whoami`/boot/overlays.old #拷贝内核 $ cp rt_kernel/kernel.img /media/`whoami`/boot/kernel.img #拷贝硬件配置 $ cp rt_kernel/bcm2835*.dtb /media/`whoami`/boot/ #拷贝overlays $ cp -r rt_kernel/overlays /media/`whoami`/boot/ #拷贝内核模块 $ sudo cp -r rt_kernel/lib/modules/* /media/`whoami`/rootfs/lib/modules/ #卸载设备 $ sudo umount -A -R -a /media/`whoami`/boot |
借助编译环境,单独编译内核模块
有时,我们需要单独编译新下载的内核驱动,这个时候,就可以使用如下的方式进行单独内核模块的编译。
下面,我们以ASIX AX88772系列的USB有线网卡驱动的编译为例:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
$ export PATH=$PATH:~/rpi/rpi-tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin $ cd ~/rpi/rpi-linux # wget https://www.mobibrw.com/wp-content/uploads/2018/09/AX88772C_772B_772A_760_772_178_LINUX_DRIVER_v4.22.0_Source.tar.bz2 $ wget http://www.asix.com.tw/FrootAttach/driver/AX88772C_772B_772A_760_772_178_LINUX_DRIVER_v4.22.0_Source.tar.bz2 $ tar xvf AX88772C_772B_772A_760_772_178_LINUX_DRIVER_v4.22.0_Source.tar.bz2 $ cd AX88772C_772B_772A_760_772_178_LINUX_DRIVER_v4.22.0_Source $ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -C ../ M=`pwd` #当前目录下就会生成 asix.ko 这个内核模块,生成的内核模块拷贝到指定的目录即可正常工作 |
解决已知问题
使用上面的命令安装完成内核后,目前(2018.09.26)遇到的问题为,当插入ASIX AX88772系列的USB有线网卡之后,会导致内核崩溃,启动失败。
设备信息如下:
|
1 |
Bus 001 Device 034: ID 0b95:7720 ASIX Electronics Corp. AX88772 |
初步怀疑是USB设备的驱动依赖关系不正确导致内核崩溃。
目前的临时解决方法为要求设备启动时候优先加载USB设备相关的驱动,而不是等到网卡插入的时候再去加载。
也就是在/boot/config.txt文件尾部新增加一行dtoverlay=dwc2。这段代码本来是为树莓派通过USB访问网络的虚拟网卡准备的(是的,你没看错,树莓派本身可以不借助网卡直接通过USB接口跟电脑共享方式上网,不过需要设置一堆东西,最简单的还是外接真正的USB网卡)。我们加载这个模块,但是并不使用这个功能,造成的结果就是重新调整了模块加载顺序,规避了后续的问题。
|
1 |
$ sed -i '$a\\ndtoverlay=dwc2' /media/`whoami`/boot/config.txt |
上述修改后,依旧存在动态插拔网卡,设备会重启的问题,不过已经不影响正常使用。
参考链接
How to Perform Real-Time Processing on the Raspberry Pi
继续阅读How to Perform Real-Time Processing on the Raspberry Pi