mirror of
https://github.com/Lost-MSth/Arcaea-server.git
synced 2026-02-11 18:47:26 +08:00
Database performance optimization for large quantities
- Add two indices for avoiding possible slow queries > This is an experimental handle for the database which has some tables over one hundred thousand lines.
This commit is contained in:
@@ -55,7 +55,6 @@ class UserDownload:
|
|||||||
self.song_id: str = None
|
self.song_id: str = None
|
||||||
self.file_name: str = None
|
self.file_name: str = None
|
||||||
|
|
||||||
self.file_path: str = None
|
|
||||||
self.token: str = None
|
self.token: str = None
|
||||||
self.token_time: int = None
|
self.token_time: int = None
|
||||||
|
|
||||||
@@ -66,6 +65,8 @@ class UserDownload:
|
|||||||
@property
|
@property
|
||||||
def is_limited(self) -> bool:
|
def is_limited(self) -> bool:
|
||||||
'''是否达到用户最大下载量'''
|
'''是否达到用户最大下载量'''
|
||||||
|
if self.user is None:
|
||||||
|
self.select_for_check()
|
||||||
self.c.execute(
|
self.c.execute(
|
||||||
'''select count(*) from user_download where user_id = :a''', {'a': self.user.user_id})
|
'''select count(*) from user_download where user_id = :a''', {'a': self.user.user_id})
|
||||||
y = self.c.fetchone()
|
y = self.c.fetchone()
|
||||||
@@ -74,27 +75,26 @@ class UserDownload:
|
|||||||
@property
|
@property
|
||||||
def is_valid(self) -> bool:
|
def is_valid(self) -> bool:
|
||||||
'''链接是否有效且未过期'''
|
'''链接是否有效且未过期'''
|
||||||
return int(time()) - self.token_time <= Constant.DOWNLOAD_TIME_GAP_LIMIT and self.song_id+'/'+self.file_name == self.file_path
|
if self.token_time is None:
|
||||||
|
self.select_for_check()
|
||||||
|
return int(time()) - self.token_time <= Constant.DOWNLOAD_TIME_GAP_LIMIT
|
||||||
|
|
||||||
def insert_user_download(self) -> None:
|
def insert_user_download(self) -> None:
|
||||||
'''记录下载信息'''
|
'''记录下载信息'''
|
||||||
self.c.execute('''insert into user_download values(:a,:b,:c)''', {
|
self.c.execute('''insert into user_download values(:a,:b,:c)''', {
|
||||||
'a': self.user.user_id, 'b': self.token, 'c': int(time())})
|
'a': self.user.user_id, 'c': self.token, 'b': int(time())})
|
||||||
|
|
||||||
def select_from_token(self, token: str = None) -> None:
|
def select_for_check(self) -> None:
|
||||||
if token is not None:
|
'''利用token、song_id、file_name查询其它信息'''
|
||||||
self.token = token
|
self.c.execute('''select user_id, time from download_token where song_id=? and file_name=? and token = ? limit 1;''',
|
||||||
self.c.execute('''select * from download_token where token = :t limit 1''',
|
(self.song_id, self.file_name, self.token))
|
||||||
{'t': self.token})
|
|
||||||
|
|
||||||
x = self.c.fetchone()
|
x = self.c.fetchone()
|
||||||
if not x:
|
if not x:
|
||||||
raise NoAccess('The token `%s` is not valid.' % self.token)
|
raise NoAccess('The token `%s` is not valid.' % self.token)
|
||||||
self.user = User()
|
self.user = User()
|
||||||
self.user.user_id = x[0]
|
self.user.user_id = x[0]
|
||||||
self.song_id = x[1]
|
self.token_time = x[1]
|
||||||
self.file_name = x[2]
|
|
||||||
self.token_time = x[4]
|
|
||||||
|
|
||||||
def generate_token(self) -> None:
|
def generate_token(self) -> None:
|
||||||
self.token_time = int(time())
|
self.token_time = int(time())
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import json
|
|||||||
|
|
||||||
# 数据库初始化文件,删掉arcaea_database.db文件后运行即可,谨慎使用
|
# 数据库初始化文件,删掉arcaea_database.db文件后运行即可,谨慎使用
|
||||||
|
|
||||||
ARCAEA_SERVER_VERSION = 'v2.9.1.1'
|
ARCAEA_SERVER_VERSION = 'v2.9.1.3'
|
||||||
|
|
||||||
|
|
||||||
def main(path='./'):
|
def main(path='./'):
|
||||||
@@ -208,9 +208,9 @@ def main(path='./'):
|
|||||||
primary key(user_id, song_id, file_name)
|
primary key(user_id, song_id, file_name)
|
||||||
);''')
|
);''')
|
||||||
c.execute('''create table if not exists user_download(user_id int,
|
c.execute('''create table if not exists user_download(user_id int,
|
||||||
token text,
|
|
||||||
time int,
|
time int,
|
||||||
primary key(user_id, token, time)
|
token text,
|
||||||
|
primary key(user_id, time, token)
|
||||||
);''')
|
);''')
|
||||||
c.execute('''create table if not exists item(item_id text,
|
c.execute('''create table if not exists item(item_id text,
|
||||||
type text,
|
type text,
|
||||||
@@ -337,6 +337,11 @@ def main(path='./'):
|
|||||||
primary key(course_id, item_id, type)
|
primary key(course_id, item_id, type)
|
||||||
);''')
|
);''')
|
||||||
|
|
||||||
|
c.execute(
|
||||||
|
'''create index best_score_1 on best_score (song_id, difficulty);''') # 排名查询优化
|
||||||
|
c.execute(
|
||||||
|
'''create index download_token_1 on download_token (song_id, file_name);''') # 下载token判断优化
|
||||||
|
|
||||||
# 搭档初始化
|
# 搭档初始化
|
||||||
char = ['hikari', 'tairitsu', 'kou', 'sapphire', 'lethe', 'hikari&tairitsu(reunion)', 'Tairitsu(Axium)', 'Tairitsu(Grievous Lady)', 'stella', 'Hikari & Fisica', 'ilith', 'eto', 'luna', 'shirabe', 'Hikari(Zero)', 'Hikari(Fracture)', 'Hikari(Summer)', 'Tairitsu(Summer)', 'Tairitsu & Trin',
|
char = ['hikari', 'tairitsu', 'kou', 'sapphire', 'lethe', 'hikari&tairitsu(reunion)', 'Tairitsu(Axium)', 'Tairitsu(Grievous Lady)', 'stella', 'Hikari & Fisica', 'ilith', 'eto', 'luna', 'shirabe', 'Hikari(Zero)', 'Hikari(Fracture)', 'Hikari(Summer)', 'Tairitsu(Summer)', 'Tairitsu & Trin',
|
||||||
'ayu', 'Eto & Luna', 'yume', 'Seine & Hikari', 'saya', 'Tairitsu & Chuni Penguin', 'Chuni Penguin', 'haruna', 'nono', 'MTA-XXX', 'MDA-21', 'kanae', 'Hikari(Fantasia)', 'Tairitsu(Sonata)', 'sia', 'DORO*C', 'Tairitsu(Tempest)', 'brillante', 'Ilith(Summer)', 'etude', 'Alice & Tenniel', 'Luna & Mia', 'areus', 'seele', 'isabelle', 'mir', 'lagrange', 'linka', 'nami', 'Saya & Elizabeth', 'lily', 'kanae(midsummer)', 'alice&tenniel(minuet)', 'tairitsu(elegy)', 'marija', 'vita', 'hikari(fatalis)']
|
'ayu', 'Eto & Luna', 'yume', 'Seine & Hikari', 'saya', 'Tairitsu & Chuni Penguin', 'Chuni Penguin', 'haruna', 'nono', 'MTA-XXX', 'MDA-21', 'kanae', 'Hikari(Fantasia)', 'Tairitsu(Sonata)', 'sia', 'DORO*C', 'Tairitsu(Tempest)', 'brillante', 'Ilith(Summer)', 'etude', 'Alice & Tenniel', 'Luna & Mia', 'areus', 'seele', 'isabelle', 'mir', 'lagrange', 'linka', 'nami', 'Saya & Elizabeth', 'lily', 'kanae(midsummer)', 'alice&tenniel(minuet)', 'tairitsu(elegy)', 'marija', 'vita', 'hikari(fatalis)']
|
||||||
|
|||||||
@@ -52,15 +52,17 @@ def download(file_path):
|
|||||||
with Connect() as c:
|
with Connect() as c:
|
||||||
try:
|
try:
|
||||||
x = UserDownload(c)
|
x = UserDownload(c)
|
||||||
x.file_path = file_path
|
x.token = request.args.get('t')
|
||||||
x.select_from_token(request.args.get('t'))
|
x.song_id, x.file_name = file_path.split('/', 1)
|
||||||
|
x.select_for_check()
|
||||||
if x.is_limited:
|
if x.is_limited:
|
||||||
raise ArcError('You have reached the download limit.', 903)
|
raise ArcError('You have reached the download limit.', 903)
|
||||||
if x.is_valid:
|
if x.is_valid:
|
||||||
x.insert_user_download()
|
x.insert_user_download()
|
||||||
return send_from_directory(Constant.SONG_FILE_FOLDER_PATH, file_path, as_attachment=True, conditional=True)
|
return send_from_directory(Constant.SONG_FILE_FOLDER_PATH, file_path, as_attachment=True, conditional=True)
|
||||||
except ArcError as e:
|
except ArcError as e:
|
||||||
app.logger.warning(format_exc())
|
if Config.ALLOW_WARNING_LOG:
|
||||||
|
app.logger.warning(format_exc())
|
||||||
return error_return(e)
|
return error_return(e)
|
||||||
return error_return()
|
return error_return()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user