Ускорение вставки точечных данных из netcdf - PullRequest
0 голосов
/ 21 января 2019

У меня есть этот netcdf данных о погоде (один из тысяч, требующих приема пищи после запроса).В настоящее время я могу вставлять каждую полосу в таблицу с поддержкой postgis со скоростью около 20-23 секунд для каждой полосы.(для ежемесячных данных есть также ежедневные данные, которые мне еще предстоит проверить.)

Я слышал о различных способах ускорения этого с помощью COPY FROM, удаления gid, использования ssds и т. д. ...но я новичок в python и понятия не имею, как сохранить данные netcdf для чего-то, что я мог бы использовать COPY FROM или какой может быть лучший маршрут.

Если у кого-то есть какие-либо идеи о том, как ускорить этоПожалуйста, поделитесь!

Вот скрипт приема

import netCDF4, psycopg2, time

# Establish connection
db1 = psycopg2.connect("host=localhost dbname=postgis_test user=********** password=********")
cur = db1.cursor()

# Create Table in postgis
print(str(time.ctime()) + " CREATING TABLE")
try:
    cur.execute("DROP TABLE IF EXISTS table_name;")
    db1.commit()
    cur.execute(
        "CREATE TABLE table_name (gid serial PRIMARY KEY not null, thedate DATE, thepoint geometry, lon decimal, lat decimal, thevalue decimal);")
    db1.commit()
    print("TABLE CREATED")
except:
    print(psycopg2.DatabaseError)
    print("TABLE CREATION FAILED")

rawvalue_nc_file = 'netcdf_file.nc'
nc = netCDF4.Dataset(rawvalue_nc_file, mode='r')
nc.variables.keys()

lat = nc.variables['lat'][:]
lon = nc.variables['lon'][:]
time_var = nc.variables['time']
dtime = netCDF4.num2date(time_var[:], time_var.units)
newtime = [fdate.strftime('%Y-%m-%d') for fdate in dtime]
rawvalue = nc.variables['tx_max'][:]

lathash = {}
lonhash = {}
entry1 = 0
entry2 = 0

lattemp = nc.variables['lat'][:].tolist()
for entry1 in range(lat.size):
    lathash[entry1] = lattemp[entry1]

lontemp = nc.variables['lon'][:].tolist()
for entry2 in range(lon.size):
    lonhash[entry2] = lontemp[entry2]

for timestep in range(dtime.size):
    print(str(time.ctime()) + " " + str(timestep + 1) + "/180")
    for _lon in range(lon.size):
        for _lat in range(lat.size):
            latitude = round(lathash[_lat], 6)
            longitude = round(lonhash[_lon], 6)
            thedate = newtime[timestep]
            thevalue = round(float(rawvalue.data[timestep, _lat, _lon] - 273.15), 3)
            if (thevalue > -100):
                cur.execute("INSERT INTO table_name (thedate, thepoint, thevalue) VALUES (%s, ST_MakePoint(%s,%s,0), %s)",(thedate, longitude, latitude, thevalue))
    db1.commit()
cur.close()
db1.close()

print(" Done!")

1 Ответ

0 голосов
/ 21 января 2019

Если вы уверены, что большую часть времени проводят в PostgreSQL, а не в каком-либо другом собственном коде, вы можете обратиться к помощникам быстрого выполнения , а именно cur.execute_values() в вашемcase.

Кроме того, вы можете убедиться, что вы находитесь в транзакции, чтобы база данных не переключалась в режим автоматической фиксации.(«Если вы не выполните команду BEGIN, то каждый отдельный оператор имеет неявный BEGIN и (в случае успеха) обернутый вокруг него COMMIT.»)

Что-то подобное может сработать, хотя и не проверялось.

for timestep in range(dtime.size):
    print(str(time.ctime()) + " " + str(timestep + 1) + "/180")
    values = []

    cur.execute("BEGIN")

    for _lon in range(lon.size):
        for _lat in range(lat.size):
            latitude = round(lathash[_lat], 6)
            longitude = round(lonhash[_lon], 6)
            thedate = newtime[timestep]
            thevalue = round(
                float(rawvalue.data[timestep, _lat, _lon] - 273.15), 3
            )
            if thevalue > -100:
                values.append((thedate, longitude, latitude, thevalue))

    psycopg2.extras.execute_values(
        cur,
        "INSERT INTO table_name (thedate, thepoint, thevalue) VALUES %s",
        values,
        template="(%s, ST_MakePoint(%s,%s,0), %s)"
    )
    db1.commit()
...